// 蜂窝蜜造平台生成代码，如手工更改，请添加到 .beeignore 忽略生成

package com.fowo.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.*;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fowo.api.common.model.R;
import com.fowo.api.controller.purchase.vo.WarehouseBinParam;
import com.fowo.api.datainterface.service.impl.DatainterfaceServiceImpl;
import com.fowo.api.datainterface.util.JsonUtil;
import com.fowo.api.datainterface.util.RedisUtil;
import com.fowo.api.entity.*;
import com.fowo.api.mapper.NavSellOrderDeclareMapper;
import com.fowo.api.model.nav.after.sell.order.NavAfterSellOrderVo;
import com.fowo.api.model.nav.logistics.channel.NavLogisticsChannelItemVo;
import com.fowo.api.model.nav.logistics.channel.NavLogisticsChannelSearchParamPo;
import com.fowo.api.model.nav.logistics.channel.issu.NavLogisticsChannelIssuItemVo;
import com.fowo.api.model.nav.logistics.channel.issu.NavLogisticsChannelIssuSearchParamPo;
import com.fowo.api.model.nav.logistics.channel.view.NavLogisticsChannelViewVo;
import com.fowo.api.model.nav.logistics.provider.NavLogisticsProviderSearchParamPo;
import com.fowo.api.model.nav.sell.order.*;
import com.fowo.api.model.nav.sell.order.declare.NavSellOrderDeclareItemVo;
import com.fowo.api.model.nav.sell.order.declare.NavSellOrderDeclareSearchParamPo;
import com.fowo.api.model.nav.sell.order.detail.NavSellOrderDetailItemVo;
import com.fowo.api.model.nav.sell.order.detail.NavSellOrderDetailSearchParamPo;
import com.fowo.api.model.nav.sell.order.platform.NavSellOrderPlatformItemVo;
import com.fowo.api.model.nav.sell.order.platform.NavSellOrderPlatformSearchParamPo;
import com.fowo.api.model.nav.sell.order.transaction.NavSellOrderTransactionItemVo;
import com.fowo.api.model.nav.sell.order.transaction.NavSellOrderTransactionSearchParamPo;
import com.fowo.api.model.product.ProductVo;
import com.fowo.api.model.purchase.order.PurchaseOrderItemVo;
import com.fowo.api.model.purchase.order.PurchaseOrderSearchParamPo;
import com.fowo.api.model.purchase.order.PurchaseOrderVo;
import com.fowo.api.model.purchase.order.product.PurchaseOrderProductItemVo;
import com.fowo.api.model.wms.order.WmsOrderVo;
import com.fowo.api.model.wms.order.item.WmsOrderItemItemVo;
import com.fowo.api.service.*;
import com.fowo.api.syncAmazon.api.FbaOutboundApiService;
import com.fowo.api.sys.annotation.DataActivity;
import com.fowo.api.sys.entity.SysBase;
import com.fowo.api.sys.entity.SysDepartment;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.entity.enums.SysDataActivityAction;
import com.fowo.api.sys.model.NewSerialRequest;
import com.fowo.api.sys.model.SysDictAllItem;
import com.fowo.api.sys.model.SysUserVo;
import com.fowo.api.sys.service.FileService;
import com.fowo.api.sys.service.SysDictService;
import com.fowo.api.sys.service.SysFileService;
import com.fowo.api.sys.service.impl.SysDepartmentServiceImpl;
import com.fowo.api.sys.service.impl.SysUserServiceImpl;
import com.fowo.api.tiktok.service.TiktokOrderService;
import com.fowo.api.user.model.JwtUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.ion.Decimal;

import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单管理 服务实现类
 *
 * @author 蜂窝蜜造平台 配置人：任凯
 */
@Service
@Slf4j
@DS("ds24")
public class NavSellOrderServiceImpl extends NavSellOrderBaseServiceImpl {

    @Resource
    private NavOrderRuleServiceImpl orderRuleService;
    @Resource
    private InventoryRealServiceImpl inventoryRealService;
    @Resource
    private NavLogisticsProviderServiceImpl logisticProviderService;
    @Resource
    private NavLogisticsChannelServiceImpl logisticsChannelService;
    @Resource
    private WmsOrderBaseServiceImpl wmsOrderService;
    @Resource
    private PurchaseOrderServiceImpl purchaseOrderService;
    @Resource
    private NavAfterSellOrderServiceImpl navAfterSellOrderService;
    @Resource
    private List<NavSellOrderLogisticsService> sellOrderLogisticsServiceList;
    @Resource
    private NavLogisticsMappingServiceImpl logisticsMappingService;
    @Resource
    private NavLogisticsChannelViewServiceImpl logisticsChannelViewService;
    @Resource
    private SysCountryServiceImpl sysCountryService;
    @Resource
    private List<IssuOrderPlatformService> issuOrderPlatformServiceList;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private WarehouseServiceImpl warehouseService;
    @Resource
    private ShopInfoServiceImpl shopInfoService;
    @Resource
    private ListingFatherServiceImpl listingFatherService;
    @Resource
    private FbaOutboundApiService fbaOutboundApiService;
    @Resource
    private NavSellOrderServiceImpl navSellOrderService;
    @Resource
    private WarehouseBinDServiceImpl warehouseBinDService;
    @Resource
    private ProductServiceImpl productService;
    @Resource
    private NavSellOrderDeclareServiceImpl navSellOrderDeclareService;
    @Resource
    private FileService fileService;
    @Resource
    private SysFileService sysFileService;
    @Resource
    private DatainterfaceServiceImpl datainterfaceService;
    @Resource
    private TiktokOrderService tiktokOrderService;

    //费用计算小数点精度
    private static volatile int round = 2;

    /**
     * 创建订单管理
     *
     * @param model 订单管理
     * @return 新数据的主键
     */

    @DataActivity(action = SysDataActivityAction.Add)
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW, readOnly = false)
    @Override
    public Long create(NavSellOrderVo model) throws Exception {
        //01 重算
        this.createOrUpdateHandler(model, true);
        //02 保存
        return super.create(model);
    }


    /**
     * 更新订单管理
     *
     * @param model 订单管理
     * @return 更新是否成功
     */
    @DataActivity(action = SysDataActivityAction.Modified)
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW, readOnly = false)
    public boolean update(NavSellOrderVo model) throws Exception {
        //01 重算
        this.createOrUpdateHandler(model, false);
        //03更新
        return super.update(model);
    }


    /**
     * 创建处理器
     *
     * @param model
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class, readOnly = false)
    public void createOrUpdateHandler(NavSellOrderVo model, boolean isCreate) throws Exception {
        this.prepareCreateOrUpdateHandler(model);
        //00 平台订单单独处理
        if (StrUtil.equals("5", model.getStatus()) && isCreate) {
            this.createHandler(model);
            return;
        }
        //01处理产品配对相关
        this.calcProduct(model);
        //02 处理规则
        if (isCreate) {
            this.orderHandler(model);
        } else {
            //去除缺货标签
            if (CollUtil.safeContains(CollUtil.newArrayList("1"), model.getDeliveryWidType())) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
                boolean haveStock = this.isHaveStock(model.getDeliveryWarehouse(), "3", model.getProduct());
                if (haveStock) {
                    model.setTag(tagHandler(model.getTag(), null, "25"));
                } else {
                    model.setTag(tagHandler(model.getTag(), null, "25"));
                }
            } else {
                model.setTag(tagHandler(model.getTag(), null, "25"));
            }
        }
        //03计算物流尺寸相关
        this.calcDelivery(model.getId(), model);
        //04报关处理
        model.setDeclare(this.calcDeclare(model.getId(), model.getProduct()));
        //05 处理交易信息
        if (isCreate) {
            model.setTransaction(this.calcTransaction(model.getId(), model.getProduct(), null));
        } else {
            model.setTransaction(this.calcTransaction(model.getId(), model.getProduct(), this.getTransaction(model.getTransaction())));
        }
        //06 处理平台信息
        model.setPlatform(this.calcPlatform(model.getId(), model.getPlatform()));
        //07 其它
        this.calcOther(model);

        if (isCreate) {
            model.setId(null);
            model.setOrderId(null);
            //07 清理
            for (NavSellOrderDetailItemVo detail : model.getProduct()) {
                detail.setId(null);
                detail.setDelFlag(false);
                detail.setParentNavSellOrder(null);
                detail.setParentNavSellOrderOrderId(model.getOrderId());
            }
            for (NavSellOrderDeclareItemVo declare : model.getDeclare()) {
                declare.setId(null);
                declare.setDelFlag(false);
                declare.setParentNavSellOrder(null);
                declare.setParentNavSellOrderOrderId(model.getOrderId());
            }
            for (NavSellOrderPlatformItemVo platform : model.getPlatform()) {
                platform.setId(null);
                platform.setDelFlag(false);
                platform.setParentNavSellOrder(null);
                platform.setParentNavSellOrderOrderId(model.getOrderId());
            }
            for (NavSellOrderTransactionItemVo transaction : model.getTransaction()) {
                transaction.setId(null);
                transaction.setDelFlag(false);
                transaction.setParentNavSellOrder(null);
                transaction.setParentNavSellOrderOrderId(model.getOrderId());
            }
        }
    }

    /**
     * 平台订单创建
     *
     * @param model
     */
    public void createHandler(NavSellOrderVo model) {
        if (ObjUtil.isNotEmpty(model.getId())) {
            SpringUtil.getBean(NavSellOrderTransactionServiceImpl.class).remove(Wrappers.<NavSellOrderTransaction>lambdaQuery().eq(NavSellOrderTransaction::getParentNavSellOrder, model.getId()));
        }
        model.setTransaction(this.calcTransaction(model.getProduct(), null));
        model.setType(CollUtil.size(model.getProduct()) > 1 ? "2" : "1"); //1: 一件一单 2: 一件多单
    }

    /**
     * 预处理
     *
     * @param model
     */
    public void prepareCreateOrUpdateHandler(NavSellOrderVo model) {
        //00 验证
        Assert.isTrue(CollUtil.safeContains(CollUtil.newArrayList(null, "1", "5"), model.getStatus()), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
        Assert.isTrue(CollUtil.size(model.getProduct()) > 0, "产品信息参数异常!");
        Assert.isTrue(CollUtil.size(model.getPlatform()) > 0, "平台信息参数异常!");
    }

    /**
     * 计算其它
     *
     * @param model
     * @throws Exception
     */
    public void calcOther(NavSellOrderVo model) throws Exception {
        String deliveryWidType = this.warehouseHandler(model.getDeliveryWarehouse());
        model.setDeliveryWidType(deliveryWidType);
        if (ObjUtil.isAllNotEmpty(model.getDeliveryLogisticsChannel())) {
            NavLogisticsChannelViewVo navLogisticsChannelViewVo = this.navLogisticsChannelViewHandler(model);
            model.setProviderName(navLogisticsChannelViewVo.getProviderName());
            if (ObjUtil.isAllNotEmpty(model.getDeliveryWidType())) {
                if (StrUtil.equals(model.getDeliveryWidType(), navLogisticsChannelViewVo.getDeliveryWidType())) {
                    model.setProviderName(navLogisticsChannelViewVo.getProviderName());
                } else {
                    Assert.isTrue(false, "发货仓库或物流方式设置错误!");
                }
            }
            model.setWarehouseActInventoryDeductionType(StrUtil.blankToDefault(model.getWarehouseActInventoryDeductionType(), "3"));
        }

        model.setTag(tagHandler(model.getTag(), null, "3,6,7,23,17"));
        if (StrUtil.hasBlank(Convert.toStr(model.getDeliveryCountry()), model.getDeliveryCity(), model.getDeliveryReceipt(), model.getDeliveryPhone(), model.getDeliveryAddress1())) {
            model.setTag(tagHandler(model.getTag(), "3"));//订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
        }
        if (CollUtil.safeContains(CollUtil.newArrayList("2"), model.getDeliveryWidType())) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
            model.setTag(tagHandler(model.getTag(), "23"));//订单标签  23:转FBA配送
        }
        if (ObjUtil.isEmpty(model.getDeliveryWarehouse())) {
            model.setTag(tagHandler(model.getTag(), "6"));//订单标签 6:未分配仓库
        }
        if (ObjUtil.isEmpty(model.getDeliveryLogisticsChannel())) {
            model.setTag(tagHandler(model.getTag(), "7"));//订单标签 7:未分配物流
        }
        if (this.hasTagHandler(model.getTag(), "23")) {
            if (!this.checkFbaData(model)) {
                model.setTag(tagHandler(model.getTag(), "17"));//订单标签 17:第三方仓商品未配对
            }
            //可用量置0
            for (NavSellOrderDetailItemVo itemVo : model.getProduct()) {
                itemVo.setAvailableQuantity(0);
            }
        }
        /*        todo 配对关系应用到其他待审核订单和商品配对
        if (StrUtil.equals("1", model.getPariLike())) {
            List<NavSellOrderDetailItemVo> nowPariProductList = model.getProduct().stream().filter(f -> StrUtil.equals("1", f.getNowPari())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(nowPariProductList)) {
                List<NavSellOrderSelectNoPariOrderIdListResult> noPariOrderIdList = null;
                for (NavSellOrderDetailItemVo itemVo : nowPariProductList) {
                    NavSellOrderSelectNoPariOrderIdListParam param = new NavSellOrderSelectNoPariOrderIdListParam();
                    param.setMsku(itemVo.getMsku());
                    param.setId(itemVo.getId());
                    noPariOrderIdList = super.selectNoPariOrderIdList(param);
                    if (CollUtil.isNotEmpty(noPariOrderIdList)) {

                    }
                }

            }
        }
        */
        model.setType(CollUtil.size(model.getProduct()) > 1 ? "2" : "1"); //1: 一件一单 2: 一件多单
        model.setPrintOrderStatus("1");
        model.setPrintFaceStatus("1");
        model.setPickingTime(null);
        model.setIssuTime(null);
        model.setIsTest("0");
        model.setIsWeigh("0");
        model.setCutStatus("0");
        model.setSplitType("0");
        model.setWmsOrderId(null);
        model.setWoNumber(null);

    }


    /**
     * 打单拣货树形列表
     *
     * @param search
     * @return
     */
    public List<CustomNavLogisticsProviderVo> searchTree(NavLogisticsProviderSearchParamPo search) {
        search.setTypeInList(CollUtil.newArrayList("1"));
        List<CustomNavLogisticsProviderVo> list = BeanUtil.copyToList(logisticProviderService.search(search), CustomNavLogisticsProviderVo.class);
        for (CustomNavLogisticsProviderVo item : list) {
            NavLogisticsChannelSearchParamPo channelSearch = new NavLogisticsChannelSearchParamPo();
            channelSearch.setStatus("1");
            channelSearch.setNavLogisticsProviderId(item.getId());
            List<NavLogisticsChannelItemVo> listItemVo = logisticsChannelService.search(channelSearch);
            item.setChannel(listItemVo);
        }
        return list;
    }


    /**
     * 测试获取盈禾物流
     *
     * @param orderId
     * @return
     */
    public Object getBillTrack(String orderId) {
        JSONObject param = new JSONObject();
        param.put("BillNo", orderId);
        Object YHWL = SpringUtil.getBean(DatainterfaceServiceImpl.class).executeInterface(null, "EC00482", null, param, null);
        return YHWL;
    }


    /**************************************订单管理逻辑******************************************/

    /**
     * 获取列表详情
     *
     * @param idList 订单管理的主键
     */
    public List<NavSellOrderVo> getVoByIdList(List<Long> idList, boolean containsSub) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        List<NavSellOrder> ls = this.listByIds(idList);
        if (CollUtil.isEmpty(ls)) {
            return null;
        }
        List<NavSellOrderVo> list = BeanUtil.copyToList(ls, NavSellOrderVo.class);
        if (containsSub) {
            NavSellOrderPlatformSearchParamPo platformSearchParamPo = new NavSellOrderPlatformSearchParamPo();
            platformSearchParamPo.setParentNavSellOrderInList(idList);
            platformSearchParamPo.applySqlSegments();
            List<NavSellOrderPlatformItemVo> platformItemVoList = navSellOrderPlatformService.search(platformSearchParamPo);
            NavSellOrderTransactionSearchParamPo transactionSearchParamPo = new NavSellOrderTransactionSearchParamPo();
            transactionSearchParamPo.setParentNavSellOrderInList(idList);
            transactionSearchParamPo.applySqlSegments();
            List<NavSellOrderTransactionItemVo> transactionItemVoList = navSellOrderTransactionService.search(transactionSearchParamPo);
            NavSellOrderDetailSearchParamPo productSearchParamPo = new NavSellOrderDetailSearchParamPo();
            productSearchParamPo.setParentNavSellOrderInList(idList);
            productSearchParamPo.applySqlSegments();
            List<NavSellOrderDetailItemVo> detailItemVoList = navSellOrderDetailService.search(productSearchParamPo);
            NavSellOrderDeclareSearchParamPo declareSearchParamPo = new NavSellOrderDeclareSearchParamPo();
            declareSearchParamPo.setParentNavSellOrderInList(idList);
            declareSearchParamPo.applySqlSegments();
            List<NavSellOrderDeclareItemVo> declareItemVoList = navSellOrderDeclareService.search(declareSearchParamPo);
            for (NavSellOrderVo item : list) {
                item.setPlatform(CollUtil.isEmpty(platformItemVoList) ? null : platformItemVoList.stream().filter(f -> NumberUtil.equals(f.getParentNavSellOrder(), item.getId())).collect(Collectors.toList()));
                item.setDeclare(CollUtil.isEmpty(declareItemVoList) ? null : declareItemVoList.stream().filter(f -> NumberUtil.equals(f.getParentNavSellOrder(), item.getId())).collect(Collectors.toList()));
                item.setProduct(CollUtil.isEmpty(detailItemVoList) ? null : detailItemVoList.stream().filter(f -> NumberUtil.equals(f.getParentNavSellOrder(), item.getId())).collect(Collectors.toList()));
                item.setTransaction(CollUtil.isEmpty(transactionItemVoList) ? null : transactionItemVoList.stream().filter(f -> NumberUtil.equals(f.getParentNavSellOrder(), item.getId())).collect(Collectors.toList()));
            }
        }
        return list;
    }

    /**
     * 获取列表详情
     *
     * @param idList 订单管理的主键
     */
    public List<NavSellOrderVo> getDeclareVoListByIdList(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        List<NavSellOrder> ls = this.listByIds(idList);
        if (CollUtil.isEmpty(ls)) {
            return null;
        }
        List<NavSellOrderVo> list = BeanUtil.copyToList(ls, NavSellOrderVo.class);
        NavSellOrderDeclareSearchParamPo declareSearchParamPo = new NavSellOrderDeclareSearchParamPo();
        declareSearchParamPo.setParentNavSellOrderInList(idList);
        declareSearchParamPo.applySqlSegments();
        List<NavSellOrderDeclareItemVo> declareItemVoList = navSellOrderDeclareService.search(declareSearchParamPo);
        for (NavSellOrderVo item : list) {
            item.setDeclare(CollUtil.isEmpty(declareItemVoList) ? null : declareItemVoList.stream().filter(f -> NumberUtil.equals(f.getParentNavSellOrder(), item.getId())).collect(Collectors.toList()));
        }

        return list;
    }


    /**
     * 判断验证
     *
     * @param navSellOrderVo
     */
    public void prepareProcess(NavSellOrderVo navSellOrderVo) {
        List<NavSellOrderDetailItemVo> productList = navSellOrderVo.getProduct();
        List<NavSellOrderPlatformItemVo> platformList = navSellOrderVo.getPlatform();
        List<NavSellOrderTransactionItemVo> transactionList = navSellOrderVo.getTransaction();
        List<NavSellOrderDeclareItemVo> declareList = navSellOrderVo.getDeclare();
        Assert.isTrue(CollUtil.isNotEmpty(productList), "订单{},产品信息参数异常!", navSellOrderVo.getOrderId());
        Assert.isTrue(CollUtil.isNotEmpty(platformList), "订单{},平台信息参数异常!", navSellOrderVo.getOrderId());
        Assert.isTrue(CollUtil.isNotEmpty(transactionList), "订单{},交易信息参数异常!", navSellOrderVo.getOrderId());
        Assert.isTrue(CollUtil.isNotEmpty(declareList), "订单{},报关信息参数异常!", navSellOrderVo.getOrderId());
        Assert.isTrue(CollUtil.allMatch(transactionList, a -> NumberUtil.isGreaterOrEqual(Convert.toBigDecimal(a.getAmount(), BigDecimal.ZERO), BigDecimal.ZERO) && NumberUtil.isGreaterOrEqual(Convert.toBigDecimal(a.getTotalAmount(), BigDecimal.ZERO), BigDecimal.ZERO)), "交易信息处理异常,商品金额或订单金额必须大于等于零!");
        BigDecimal detailQuantity = NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getQuantity).toArray(Integer[]::new));
        BigDecimal declareQuantity = NumberUtil.add(declareList.stream().map(NavSellOrderDeclareItemVo::getQuantity).toArray(Integer[]::new));
        Assert.isTrue(NumberUtil.equals(detailQuantity, declareQuantity), "订单{},报关数量与产品数量不一致!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryLogisticsChannel()), "订单{},物流方式未填写!", navSellOrderVo.getOrderId());

        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryCountry()), "订单{},国家/地区未填写!", navSellOrderVo.getOrderId());
//        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryProvince()), "订单{},省/州未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryCity()), "订单{},城市未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryAddress1()), "订单{},详细地址1未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryReceipt()), "订单{},收件人未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryPhone()), "订单{},电话未填写!", navSellOrderVo.getOrderId());


        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryLogisticsChannel()), "订单{},物流方式未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getProviderName()), "订单{},物流商未填写!", navSellOrderVo.getOrderId());
        Assert.isTrue(ObjUtil.isAllNotEmpty(navSellOrderVo.getDeliveryWidType()), "订单{},发货仓属性未填写!", navSellOrderVo.getOrderId());
        if (this.hasTagHandler(navSellOrderVo.getTag(), "23")) {
            Assert.isTrue(this.checkFbaData(navSellOrderVo), "订单{},第三方仓商品未配对!", navSellOrderVo.getOrderId());
        }
        Assert.isTrue(navSellOrderVo.getDeclare().stream().allMatch(a -> StrUtil.isAllNotBlank(a.getChineseName(), a.getEnglishName())), "校验异常,中文、英文报关名信息!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
        Assert.isTrue(navSellOrderVo.getDeclare().stream().allMatch(a -> NumberUtil.isGreater(Convert.toBigDecimal(a.getQuantity(), BigDecimal.ZERO), BigDecimal.ZERO)), "校验报关数量必须大于0!");
        Assert.isTrue(navSellOrderVo.getDeclare().stream().allMatch(a -> NumberUtil.isGreater(Convert.toBigDecimal(a.getPackingWeight(), BigDecimal.ZERO), BigDecimal.ZERO)), "校验报关重量必须大于0!");
    }

    /**
     * 转成销售订单
     *
     * @param source
     * @return
     */
    private WmsOrderVo translateWmsOrder(NavSellOrderVo source) throws Exception {
        if (ObjUtil.isEmpty(source)) {
            return null;
        }
        NavSellOrderPlatformItemVo platform = CollUtil.getFirst(source.getPlatform());
        NavSellOrderTransactionItemVo transaction = this.getTransaction(source.getTransaction());
        //获取当前用户
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        //主表构建
        WmsOrderVo target = new WmsOrderVo();
        target.setWoNumber(sysSerialService.getNewSerial(new NewSerialRequest(null, "WmsOrder.woNumber")));
        target.setParentNavSellOrder(source.getId());//id
        target.setOrderNumber(source.getOrderId());//系统单号
        target.setStatus("1"); //状态:发货中
        target.setPlatformOrderNo(platform.getPlatformOrderId());//平台单号
        target.setPlatformName(platform.getPlatform()); //平台
        target.setLogisticsProviderId(source.getProviderName());//物流服务商
        target.setLogisticsTypeId(Convert.toStr(source.getDeliveryLogisticsChannel()));//物流方式  source.getDeliveryLogisticsChannel()
        target.setTagNames(this.getTagHandler(source.getTag()));
        target.setSid(source.getShopInfo());//店铺
        target.setSiteText(SpringUtil.getBean(SysRegionService.class).getNameById(source.getSite()));//站点名称
        //如果存在当前用户
        if (currentUser != null) {
            target.setDeliverer(Convert.toStr(currentUser.getDisplayName()));//发货人 编号 or 名称 ?
        }
        target.setTargetCountry(sysCountryService.getCountryById(source.getDeliveryCountry()));//国家
        target.setRecipientTaxNo(source.getDeliveryRecipientTaxNo());//收件人税号
        target.setWaybillNo(source.getDeliveryWaybillId());//运单号
        target.setTrackingNo(source.getDeliveryTrackId());//跟踪号
        target.setWid(source.getDeliveryWarehouse());//仓库
        target.setLogisticsEstimatedFreight(source.getDeliveryThinkFreight());//预估运费
        target.setLogisticsFreight(source.getDeliveryRealFreight());//物流运费

        target.setPkgLength(source.getDeliveryRealSizeLength());//包裹尺寸长
        target.setPkgHeight(source.getDeliveryRealSizeHeight());//包裹尺寸高
        target.setPkgRealWeight(source.getDeliveryRealWeight());//包裹实重
        target.setPkgWeight(source.getDeliveryThinkWeight());//估算重量
        target.setOrderType(source.getType());//订单类型
        target.setRecipient(source.getDeliveryReceipt());//收件人
        target.setPhone(source.getDeliveryPhone());//电话
        target.setZipCode(source.getDeliveryZipCode());//邮编
        target.setAddress(source.getDeliveryAddress1());//收货地址
        target.setOrderOriginAmount(NumberUtil.toStr(transaction.getTotalAmount(), "0"));//订单金额
        target.setDeliverDeadline(DateUtil.formatDateTime(platform.getLatestShipTime()));//发货时限
        target.setOrderCustomerServiceNotes(source.getRemark());//客服备注
        target.setOrderBuyerNotes(source.getBuyerLeaveWord());//买家留言
        target.setPkgVolume(source.getDeliveryRealVolume());//包裹体积

        target.setOrderFrom(source.getSource());//订单来源

        target.setLogisticsStatus(source.getDeliveryStatus());//物流下单状态 (1 - 待导入; 2 - 物流待下单; 3 -  物流下单中; 4 - 下单异常; 5 -  下单完成; 6 - 待海外仓下单; 7 - 海外仓下单中; 11 - 待导入国内物流; 41 - 物流取消中; 42 - 物流取消异常; 43 - 物流取消完成; )
        target.setLogisticsMessage(source.getDeliveryMessage());//物流下单消息
        target.setOrderCurrencyCode(source.getCurrency());//订单币种
        target.setSellerName(SpringUtil.getBean(ShopInfoService.class).getShopNameById(source.getShopInfo()));//店铺名称
        target.setLogisticsProviderName(source.getProviderName());//物流服务商名称
        target.setLogisticsTypeName(logisticsChannelViewService.getLabelById(source.getDeliveryLogisticsChannel()));//物流方式名称
        target.setPkgWidth(source.getDeliveryRealSizeWidth());//包裹尺寸宽
        target.setPkgFeeWeight(source.getDeliveryRealFeeWeight());//包裹计费重
        target.setPkgWeightUnit(source.getDeliveryThinkWeightUnit());//预估重量单位
        target.setPkgRealWeightUnit(source.getDeliveryRealWeightUnit());//包裹实重单位
        target.setPkgFeeWeightUnit(source.getDeliveryRealFeeWeightUnit());//包裹计费重单位
        target.setPkgSizeUnit(source.getDeliveryRealSizeUnit());//包裹尺寸单位
        target.setLogisticsEstimatedFreightCurrencyCode(source.getDeliveryRealCurrencyCode());//预估运费币种
        target.setLogisticsFreightCurrencyCode(source.getDeliveryRealCurrencyCode());//物流运费币种
        target.setSenderTaxNo(source.getDeliverySenderTaxNo());//发件人税号
        target.setCity(source.getDeliveryCity());//城市
        target.setProvinceState(source.getDeliveryProvince());//省/州
        target.setDistrictCounty(source.getDeliveryArea());//区/县
        target.setHouseNumber(source.getDeliveryHouseNumber());//门牌号
        target.setIsOperation("1");//是否操作库存
        target.setWName(SpringUtil.getBean(WarehouseService.class).getNameById(source.getDeliveryWarehouse()));//仓库名称
        target.setWoId(null);//领星销售出库单ID
        target.setCreateTime(new Date());
        target.setLastUpdateTime(new Date());
        //20240412新增
        target.setBuyerEmail(source.getBuyerEmail());
        target.setIsSurfacePrint(StrUtil.blankToDefault(source.getPrintFaceStatus(),"0"));
        target.setIsorderPrint(StrUtil.blankToDefault(source.getPrintOrderStatus(),"0"));
        target.setIsCheck(StrUtil.blankToDefault(source.getIsTest(),"0"));
        target.setIsWeigh(StrUtil.blankToDefault(source.getIsWeigh(),"0"));
        //如果存在当前用户
        if (currentUser != null) {
            target.setCreateUser(currentUser.getUserId());
            target.setLastUpdateUser(currentUser.getUserId());
        }
        //子表构建
        List<WmsOrderItemItemVo> sourceItemList = new ArrayList<>();
        for (NavSellOrderDetailItemVo product : source.getProduct()) {
            WmsOrderItemItemVo targetItem = new WmsOrderItemItemVo();
            targetItem.setParentIdOrderNumber(source.getOrderId()); //关联父级的系统单号
            targetItem.setWodId(null);//出库单明细id
            targetItem.setProductId(Convert.toLong(product.getProductId()));//商品
            targetItem.setImg(product.getImg());
            targetItem.setProductIdName(product.getProductIdName());//关联商品的品名
            targetItem.setSku(product.getSku());//SKU
            targetItem.setUnitPrice(product.getPrice());//商品单价
            targetItem.setCount(product.getQuantity());//数量
            targetItem.setCustomization(product.getRemark());//商品备注
            targetItem.setBundleType(product.getBundleType());//捆绑类型
            targetItem.setBundleWodId(product.getBundleWodId());//捆绑产品wod_id【只有拆分子产品才有】
            targetItem.setSellerSku(product.getMsku());//MSKU
            targetItem.setCnName(product.getChineseName());//中文申报名
            targetItem.setEnName(product.getEnglishName());//英文申报名
            targetItem.setCurrencyCode(source.getCurrency());//币种
            targetItem.setApportionFreight(source.getDeliveryRealFreight());//分摊运费 (总计)  ??
            targetItem.setApportionFreightSingle(source.getDeliveryRealFreight());//分摊运费 (单个) ??
            targetItem.setLogisticsFreightCurrencyCode(source.getDeliveryRealCurrencyCode());//物流运费币种
            targetItem.setWoId(null);//领星销售出库单ID
            targetItem.setCreateTime(new Date());
            targetItem.setLastUpdateTime(new Date());
            targetItem.setReferenceId(product.getReferenceId());

            if (StrUtil.equals("1", source.getDeliveryWidType()) /*&& !this.hasTagHandler(item.getTag(), "28")*/) {
                WarehouseBinParam param = new WarehouseBinParam();
                param.setWarehouseId(source.getDeliveryWarehouse());
                param.setSku(product.getSku());
                param.setType(5L);
                List<WarehouseBin> stockInBinList = warehouseBinDService.getStockInBinPage(param).getRecords();
                Assert.isTrue(CollUtil.isNotEmpty(stockInBinList), "仓位不存在!");
                targetItem.setWhbId(CollUtil.getFirst(stockInBinList).getId());
            }
            //如果存在当前用户
            if (currentUser != null) {
                targetItem.setCreateUser(currentUser.getUserId());
                targetItem.setLastUpdateUser(currentUser.getUserId());
            }
            sourceItemList.add(targetItem);
        }
        target.setProductInfo(sourceItemList);
        return target;
    }

    /**
     * 审核 :审核指确定订单需安排发货，需要将订单推送到物流做物流下单和推送给仓库做打单拣货出库，是【待审核】页面的最终操作。审核成功后，订单进入【待发货】页面。
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了审核操作")
    @Override
    public void process(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        List<NavSellOrderVo> list = this.getVoByIdList(idList, true);
        Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
        Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("1"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
        final List<WmsOrder> repeatList = wmsOrderService.list(Wrappers.<WmsOrder>lambdaQuery().in(WmsOrder::getOrderNumber, list.stream().map(m -> m.getOrderId()).collect(Collectors.toList())));
        Assert.isTrue(CollUtil.isEmpty(repeatList), "重复生成销售出库单,单号:{}", repeatList.stream().map(m -> m.getOrderNumber()).collect(Collectors.joining(",")));
        //审核逻辑
        navSellOrderService.doProcess(list);
        //物流下单
        navSellOrderService.doLogisticsOrder(list);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public List<NavSellOrderVo> doProcess(List<NavSellOrderVo> list) throws Exception {
        try {
            for (NavSellOrderVo voById : list) {
                //订单管理判断平台信息
                this.prepareProcess(voById);
                //02 生成销售出库单（发货中状态）
                WmsOrderVo wmsOrderVoItem = this.translateWmsOrder(voById);
                wmsOrderService.create(wmsOrderVoItem);
                voById.setWmsOrderId(wmsOrderVoItem.getId());
                voById.setWoNumber(wmsOrderVoItem.getWoNumber());
                voById.setPrintFaceStatus("0");
                voById.setPrintOrderStatus("0");
                voById.setDistributionStatus("2"); //1:未配货 2:已配货
                voById.setProcessTime(new Date()); //审核时间

                if (StrUtil.equals("1", voById.getDeliveryWidType()) /*&& !this.hasTagHandler(voById.getTag(), "28")*/) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
                    //01 锁库存_即时
                    //super.locksInventory(voById.getId());
                    //锁库存_仓位
                    //super.lockpInventory(voById.getId());
                    //订单锁库存（锁库存_即时）
                    wmsOrderService.locksInventory(voById.getWmsOrderId());
                    //订单锁库存（锁库存_仓位）
                    wmsOrderService.lockpInventory(voById.getWmsOrderId());
                }
            }
            //03 更新状态   1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            this.changeNavSellOrderStatus(list, "3");
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
        return list;
    }


    public void doLogisticsOrder(List<NavSellOrderVo> list) throws Exception {
        for (NavSellOrderVo voById : list) {
            String errMsg = null;
            String logisticsOrderStatus = "-1";
            try {
                Optional<NavSellOrderLogisticsService> baseService = StreamUtil.of(sellOrderLogisticsServiceList).filter(f -> StrUtil.equalsIgnoreCase(f.getType(), voById.getProviderName())).findFirst();
                if (baseService.isPresent()) {
                    SubmitOrderResult res = baseService.get().submitLogisticsOrder(voById);
                    if (res.getSuccess()) {
                        if (StrUtil.equals("1", voById.getDeliveryWidType())) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
                            /* http://www.eboexp.com/corp/webservice.htm */
                            //处理发货信息
                            voById.setDeliveryWaybillId(res.getOrderId());
                            voById.setDeliveryTrackId(res.getTrackingNumber());
                            voById.setDeliveryPartnerOrderId(res.getPartnerOrderId());
//                            if (CollUtil.isEmpty(res.getData())) {
//                                NavSellOrderFaceVo faceModel = new NavSellOrderFaceVo();
//                                faceModel.setParentNavSellOrder(voById.getId());
//                                faceModel.setFiles(res.getData());
//                                navSellOrderFaceService.create(faceModel);
//                            }
                            logisticsOrderStatus = "2";
                        } else if (CollUtil.safeContains(CollUtil.newArrayList("2"), voById.getDeliveryWidType())) {
                            //处理发货信息
                            voById.setDeliveryTime(DateUtil.date());
                            logisticsOrderStatus = "1";
                        } else {
                            errMsg = "发货方式错误";
                        }
                    } else {
                        errMsg = StrUtil.concat(true, "物流下单:返回错误信息,详情:", res.getMessage());
                    }
                } else {
                    errMsg = StrUtil.concat(true, "物流下单:未实现对应物流商接口", voById.getProviderName());
                }
            } catch (Exception ex) {
                errMsg = StrUtil.concat(true, "物流下单:发生异常:", StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            } finally {
                try {
                    voById.setErrorMessage(errMsg);
                    voById.setLogisticsOrderStatus(logisticsOrderStatus);
                    redisUtil.ListLeftPush("LogisticsOrderSuccess", StrUtil.concat(true, "记录时间:", DateUtil.now(), ",单号:", Convert.toStr(voById.getOrderId())));
                    this.updateById(BeanUtil.copyProperties(voById, NavSellOrder.class));
                } catch (Exception ex) {
                    redisUtil.ListLeftPush("LogisticsOrderException", StrUtil.concat(true, "记录时间:", DateUtil.now(), ",单号:", Convert.toStr(voById.getOrderId()), " , 异常信息:", StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000), " , 单据信息:", errMsg, " , 原始单据内容:", JsonUtil.getObjectToString(voById)));
                }
            }
        }

    }


    /**
     * 订单发货 :订单包裹完成打包、贴单后，即确认完成订单发货流程，可以操作[发货]。该操作是当前状态的最终操作，发货后，订单状态将流转为【已发货】，订单商品库存将会从锁定库存变更为扣减库存，订单发货流程结束。
     * 订单管理:发货后物流下单,创建打单拣货
     * 打单拣货:发货后扣减库存,创建订单待标发,打单拣货完成即完成订单管理
     * 补发售后订单:创建即扣减库存,审核后物流下单,处理中系统自动同步三方接口更新到完成状态
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了订单发货操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void deliver(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, true);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("3"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            this.changeNavSellOrderStatus(list, "4");
            for (NavSellOrderVo voById : list) {
                voById.setDistributionTime(new Date());//配货时间
                voById.setPickingDeliveryTime(new Date());//发货时间
                if (CollUtil.safeContains(CollUtil.newArrayList("1"), voById.getDeliveryWidType())) {
                    //02 通知销售出库单扣库存
//                    if (!this.hasTagHandler(voById.getTag(), "28")) {
//                        wmsOrderService.lockStockOut(voById.getWmsOrderId());
//                        //wmsOrderService.subInventory(wmsOrderService.getIdByOrderNumber(voById.getOrderId()));
//                    }
                    wmsOrderService.lockStockOut(voById.getWmsOrderId());
                    this.createIssu(voById);
                    //自动标发
                    if (StrUtil.equals(voById.getIssuActRules(), "1")) {   //自动标发 || 不标发
                        this.markDelivery(CollUtil.newArrayList(voById));   // 1:自动标发 2:不标发
                    } else if (StrUtil.equals(voById.getIssuActRules(), "2")) {  //1:自动标发 2:不标发
                        this.unMarkDelivery(CollUtil.newArrayList(voById));
                    }
                }
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                voById.setLastUpdateTime(new Date());
                //如果存在当前用户
                if (currentUser != null) {
                    voById.setLastUpdateUser(currentUser.getUserId());
                }
            }
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
            //03 更新售出库单状态   1:物流下单 2:发货中 3:已发货 -1:已取消
            this.changeWmsOrderStatus(list, "3");
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void createIssu(NavSellOrderVo voById) {
        voById.setDeliveryIssuId(StrUtil.equals("2", CollUtil.getFirst(voById.getPlatform()).getIssuCode()) ? voById.getDeliveryWaybillId() : voById.getDeliveryTrackId());//1:使用跟踪号 2:使用运单号
        voById.setDeliveryTime(DateUtil.date());
        voById.setIssuStatus("1"); //创建标发
        voById.setIssuTime(new Date());
        navSellOrderService.updateById(voById);
    }


    /**
     * 标发
     */
    public void markDelivery(List<NavSellOrderVo> list) throws Exception {
        //01更新标发状态  1:待标发 2:标发数据更新 3:标发中 4:标发失败 5:标发成功 -1:不标发
        for (NavSellOrderVo voById : list) {
            String errMsg = null;
            String issuStatus = "4";
            try {
                Assert.isTrue(StrUtil.isNotBlank(voById.getDeliveryIssuId()), "标发异常:包含物流未完成的单据,!");
                Optional<IssuOrderPlatformService> baseService = StreamUtil.of(issuOrderPlatformServiceList).filter(f -> StrUtil.equalsIgnoreCase(f.getType(), CollUtil.getFirst(voById.getPlatform()).getPlatform())).findFirst();
                if (baseService.isPresent()) {
                    //平台更新标发
                    R r = baseService.get().markIssu(voById);
                    if (r.isSuccess()) {
                        issuStatus = "5";
                    } else {
                        errMsg = r.getErrorMessage();
                    }
                } else {
                    errMsg = StrUtil.concat(true, "标发异常:未实现对应平台标发接口", CollUtil.getFirst(voById.getPlatform()).getPlatform());
                }
            } catch (Exception ex) {
                errMsg = StrUtil.concat(true, "标发异常:,详情:", StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            } finally {
                try {
                    if (StrUtil.isNotEmpty(errMsg)) {
                        voById.setIssuStatusExplain(errMsg);
                    }
                    voById.setIssuNumber(Convert.toInt(voById.getIssuNumber(), 0) + 1);
                    voById.setIssuStatus(issuStatus);
                    redisUtil.ListLeftPush("IssuOrderSuccess", StrUtil.concat(true, "记录时间:", DateUtil.now(), ",单号:", Convert.toStr(voById.getOrderId())));
                    navSellOrderService.updateById(BeanUtil.copyProperties(voById, NavSellOrder.class));
                } catch (Exception ex) {
                    redisUtil.ListLeftPush("IssuOrderException", StrUtil.concat(true, "记录时间:", DateUtil.now(), ",单号:", Convert.toStr(voById.getOrderId()), " , 异常信息:", StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000), " , 单据信息:", errMsg, " , 原始单据内容:", JsonUtil.getObjectToString(voById)));
                }
            }
        }
    }

    /**
     * 不标发
     */
    @Transactional(rollbackFor = Exception.class)
    public void unMarkDelivery(List<NavSellOrderVo> list) throws Exception {
        //01更新标发状态  1:待标发 2:标发数据更新 3:标发中 4:标发失败 5:标发成功 -1:不标发
        navSellOrderService.changeIssuOrderIssuStatus(list, "-1", null);
    }

    /**
     * 截单 :发货过程中，遇到因买家取消、运营取消等原因需要终止发货的，操作【截单】可以将订单回退到【待审核】状态，对于使用三方物流的订单，截单将会取消已下达的物流订单，对于使用三方海外仓发货的订单，截单会从海外仓撤回发货订单。
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了截单操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void cut(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "截单参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("3"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            for (NavSellOrderVo item : list) {
                //03 还回库存
                if (StrUtil.equals("1", item.getDeliveryWidType()) /*&& !this.hasTagHandler(item.getTag(), "28")*/) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
                    //01 锁库存_即时
                    //super.addsInventory(item.getId());
                    //锁库存_仓位
                    //super.addpInventory(item.getId());
                    //订单(取消锁库存_即时)
                    wmsOrderService.cancelLocksInventory(item.getWmsOrderId());
                    //订单（取消锁库存_仓位）
                    wmsOrderService.cancelLockpInventory(item.getWmsOrderId());
                } else if (StrUtil.equals("2", item.getDeliveryWidType())) { //1 - 本地仓; 2 - 海外仓; 3 - FBA
                    //通知物流截单
                    fbaOutboundApiService.cancelFulfillmentOrder(item.getOrderId(), item.getDeliveryWarehouse());
                }
                item.setCutStatus("1"); //1:截单中 2:异常
                item.setIssuStatus("0"); //标发状态
                item.setIssuStatusExplain("");
                item.setLogisticsOrderStatus("0");//物流下单状态
                item.setErrorMessage("");
                //item.setTag(this.tagHandler(item.getTag(), null, "23"));
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                item.setLastUpdateTime(new Date());
                //如果存在当前用户
                if (currentUser != null) {
                    item.setLastUpdateUser(currentUser.getUserId());
                }
            }
            //更新状态 // 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            this.changeNavSellOrderStatus(list, "1");
            //删除销售出库单
            this.deleteWmsOrder(list);
            //004 更新订单管理信息
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    /**
     * 获取打单\面单\发货单打印主表信息
     *
     * @param param
     * @return
     */
    public List<?> selectCustomPrint(NavSellOrderSelectPrintParam param) throws Exception {
        Assert.isTrue(ObjUtil.isAllNotEmpty(param, param.getIds(), param.getType()), "参数错误!");
        List<NavSellOrderSelectPrintResult> base = this.selectPrint(param);
        List<CustomNavSellOrderSelectPrintResult> recordList = BeanUtil.copyToList(base, CustomNavSellOrderSelectPrintResult.class);
        if (CollUtil.isEmpty(recordList)) {
            return recordList;
        }
        try {
            List<NavSellOrderVo> voByIdList = this.getVoByIdList(recordList.stream().map(m -> m.getId()).collect(Collectors.toList()), true);
            String boxId = IdUtil.getSnowflakeNextIdStr();
            for (CustomNavSellOrderSelectPrintResult record : recordList) {
                NavSellOrderVo voById = CollUtil.findOne(voByIdList, m -> m.getId().equals(record.getId()));
                NavSellOrderSelectPrintDetailParam printDetailParam = new NavSellOrderSelectPrintDetailParam();
                printDetailParam.setId(record.getId());
                record.setBoxId(boxId);
                record.setList(this.selectPrintDetail(printDetailParam));
                record.setFaceList(this.getFacePDF(voById, Convert.toBool(param.getUseCache(), true), Convert.toInt(param.getDpi(), 1024)));
                switch (param.getType()) {
                    case 1:
                        voById.setPickingTime(new Date()); //打单时间
                        voById.setPrintOrderStatus("1"); //发货单打印
                        voById.setBoxId(boxId);
                        break;
                    case 2:
                    case 3:
                        voById.setPrintFaceStatus("1");//面单打印
                        break;
                }
            }
            navSellOrderService.updateBatchById(BeanUtil.copyToList(voByIdList, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
        return recordList;
    }

    /**
     * 获取打单\面单\发货单打印主表信息
     */
    public List<NavSellOrderSelectTagCountResult> selectCustomTagCount(NavSellOrderSearchParamPo search) {
        Page<NavSellOrderSelectTagCountResult> basePage = this.selectTagCount(search);
        return basePage.getRecords();
    }

    /**
     * 获取API对接物流渠道
     *
     * @param model 订单
     * @return
     * @throws Exception
     */
    private NavLogisticsChannelViewVo navLogisticsChannelViewHandler(NavSellOrderVo model) throws Exception {
        if (ObjUtil.isEmpty(model.getDeliveryLogisticsChannel())) {
            return null;
        }
        NavLogisticsChannelViewVo channelVo = logisticsChannelViewService.getVoById(model.getDeliveryLogisticsChannel());
        if (StrUtil.equals("1", channelVo.getDeliveryWidType())) {
            NavLogisticsChannelIssuSearchParamPo issuSearchParamPo = new NavLogisticsChannelIssuSearchParamPo();
            issuSearchParamPo.setParentNavLogisticsChannel(channelVo.getId());
            issuSearchParamPo.applySqlSegments();
            List<NavLogisticsChannelIssuItemVo> issuSearch = SpringUtil.getBean(NavLogisticsChannelIssuService.class).search(issuSearchParamPo);

//            NavLogisticsChannelAddressSearchParamPo addressSearchParamPo = new NavLogisticsChannelAddressSearchParamPo();
//            addressSearchParamPo.setParentNavLogisticsChannel(channelVo.getId());
//            addressSearchParamPo.applySqlSegments();
//            List<NavLogisticsChannelAddressItemVo> addressSearch = SpringUtil.getBean(NavLogisticsChannelAddressService.class).search(addressSearchParamPo);
            //标发设置
            for (NavSellOrderPlatformItemVo platformList : model.getPlatform()) {
                NavLogisticsChannelIssuItemVo issuItemVo = CollUtil.findOne(ObjUtil.isEmpty(issuSearch) ? null : issuSearch, f -> StrUtil.equalsIgnoreCase(f.getPlatform(), platformList.getPlatform()));
                if (ObjUtil.isEmpty(issuItemVo)) {
                    platformList.setIssuCode("1");
                    continue;
                }
                platformList.setCarrier(issuItemVo.getCarrier());
                platformList.setIssuCode(issuItemVo.getCode());
                platformList.setDeliveryService(issuItemVo.getDeliveryService());
                platformList.setSearchAddress(issuItemVo.getSearchAddress());
            }

        } else if (StrUtil.equals("2", channelVo.getDeliveryWidType())) {
//            NavLogisticsWarehouseIssuSearchParamPo issuSearchParamPo = new NavLogisticsWarehouseIssuSearchParamPo();
//            issuSearchParamPo.setParentNavLogisticsWarehouse(channelVo.getId());
//            issuSearchParamPo.applySqlSegments();
//            List<NavLogisticsWarehouseIssuItemVo> issuSearch = SpringUtil.getBean(NavLogisticsWarehouseIssuService.class).search(issuSearchParamPo);
            //标发设置
            for (NavSellOrderPlatformItemVo platformList : model.getPlatform()) {
                platformList.setIssuCode("1");
            }
        }
        return channelVo;
    }


    /**
     * 获取发货仓库
     *
     * @param deliveryWarehouse 订单
     * @return
     * @throws Exception
     */

    public String warehouseHandler(Long deliveryWarehouse) throws Exception {
        if (ObjUtil.isEmpty(deliveryWarehouse)) {
            return null;
        }
        Warehouse warehouseVo = SpringUtil.getBean(WarehouseServiceImpl.class).getById(deliveryWarehouse);
        if (ObjUtil.isEmpty(warehouseVo)) {
            return null;
        }
        return warehouseVo.getWidType();
    }


    /**
     * 不发货 :【不发货】状态指订单不需要在领星ERP操作发货的订单，相当于将订单归档记录。不发货包含系统自动流转为不发货（系统初始同步店铺订单，如果订单状态是已发货、已取消等状态，为避免重复发货，订单会自动标记为不发货），和用户手动标记为不发货的订单；
     * 不发货状态订单，支持转到【待审核】，恢复发货操作：勾选订单并点击[标记处理]，选择对应处理类型，订单会流转回【待审核】状态，订单操作可以同普通订单执行发货操作。
     * <p>
     * 买家取消订单，需要设置订单不发货了
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了不发货操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void noDeliver(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("-2"), a.getStatus())), "校验异常,请先冻结!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            this.changeNavSellOrderStatus(list, "-1");
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 冻结 :待审核的订单冻结
     * <p>
     * 联系买家未回复的情况，不确定怎么发货，先冻结订单控制不能审核
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了冻结操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void freeze(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("1"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            //订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
            //26:冻结订单 27:风险订单 28:补发订单
            this.changeNavSellOrderTag(list, "26", null);
            this.changeNavSellOrderStatus(list, "-2");
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 取消冻结 :冻结的订单冻结
     * <p>
     * 订单恢复正常可以审核
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了取消冻结操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void unFreeze(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("-2"), a.getStatus())), "校验异常,请检查单据状态!");/// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            //订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
            //26:冻结订单 27:风险订单 28:补发订单
            this.changeNavSellOrderTag(list, null, "26");
            this.changeNavSellOrderStatus(list, "1");
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 标记标签
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了标记标签操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void changeTag(List<Long> idList, String tag, String removeTag) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            this.changeNavSellOrderTag(list, tag, removeTag);
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    /**
     * 留言已处理:系统同步买家留言的订单，需标记留言已处理后才能继续推送订单进行发货，可批量标记订单留言已处理。
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了留言已处操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customLeaveMessageProcessed(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(idList, false);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("1"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            for (NavSellOrder item : list) {
                item.setTag(tagHandler(item.getTag(), "24"));//订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                item.setLastUpdateTime(new Date());
                //如果存在当前用户
                if (currentUser != null) {
                    item.setLastUpdateUser(currentUser.getUserId());
                }
            }
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 设定仓库物流 :订单发货需要明确的发货仓库和物流方式；
     * 设定仓库，该订单在审核后将推送发货任务到指定仓库，由指定仓库操作发货，并扣减该仓库库存；仓库支持选择系统已有的本地仓库、海外仓库；
     * 设定物流，该订单在审核后将向该物流下达物流订单，以获取物流面单和跟踪号；物流支持选择系统已对接的三方物流、海外仓物流或自定义物流；
     * 在设置物流时，如果已明确订单需使用的物流方式，选择固定物流并选择即可；如果考虑选择价格更优的物流方式，可选择【物流比价】，在指定物流中多选物流商或渠道，系统将在所选范围选中价格最低的物流方式
     * <p>
     * 希音可以用亚马逊的物流，沃尔玛不可以，可以指定店铺的物流
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了设定仓库物流操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customLogisticsWarehouseSet(CustomNavSellOrderLogisticsWarehouseSetActionVo vo) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(vo.getIdList()), "请选择订单!");
        Assert.isTrue(ObjUtil.isAllNotEmpty(vo.getDeliveryWarehouse(), vo.getWarehouseActInventoryDeductionType(), vo.getDeliveryLogisticsChannel()), "参数验证错误!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(vo.getIdList(), true);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("1", "6"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            for (NavSellOrderVo byIdVo : list) {
                byIdVo.setDeliveryWarehouse(vo.getDeliveryWarehouse());
                byIdVo.setDeliveryLogisticsChannel(vo.getDeliveryLogisticsChannel());
                byIdVo.setWarehouseActInventoryDeductionType(vo.getWarehouseActInventoryDeductionType());
                this.update(byIdVo);
            }
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 编辑订单信息 :为快速调整同类型订单信息，系统支持快速批量编辑订单信息，包含收件地址、寄件税号等；
     * 勾选需编辑的订单，点击【编辑订单信息】，在弹出列表单个或批量编辑订单信息，点击【确定】即可完成修改。
     * <p>
     * 修改地址，换货换字母
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了编辑订单信息编辑订单信息操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customEditOrder(List<NavSellOrderItemVo> volist) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(volist), "请选择订单!");
        try {
            List<NavSellOrder> list = new ArrayList<>();
            for (NavSellOrderItemVo item : volist) {
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                NavSellOrder entity = BeanUtil.copyProperties(item, NavSellOrder.class);
                entity.setLastUpdateTime(new Date());
                if (currentUser != null) {
                    entity.setLastUpdateUser(currentUser.getUserId());
                }
                CollUtil.addAll(list, entity);
            }
            this.updateBatchById(list);
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 可合并分页列表
     */

    public Page<?> joinPageSearch(NavSellOrderSearchParamPo param, boolean withChild) {
//       V1版本
//        Page<NavSellOrderSelectJoinOrderResult> basePage = this.selectJoinOrder(param);
//        Page<CustomNavSellOrderSelectJoinOrderResult> page = BeanUtil.copyProperties(basePage, Page.class, "records");
//        List<CustomNavSellOrderSelectJoinOrderResult> records = BeanUtil.copyToList(basePage.getRecords(), CustomNavSellOrderSelectJoinOrderResult.class);
//        if (CollUtil.isEmpty(records)) {
//            return page;
//        }
//        for (CustomNavSellOrderSelectJoinOrderResult record : records) {
//            NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
//            paramPo.setPageSize(Integer.MAX_VALUE);
//            List<Long> split = Convert.toList(Long.class, StrUtil.split(record.getJoinId(), ","));
//            paramPo.setSelectedIds(split);
//            record.setList(withChild ? this.canJoinOrderPageWithChildSearch(paramPo) : this.canJoinOrderPage(paramPo));
//        }
//        page.setRecords(records);
//        return page;
//       V2版本
//        Page<NavSellOrderSelectJoinOrderResult> pageResult = this.selectJoinOrder(param);
//        Page<JSONObject> withChildPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
//        withChildPage.setRecords(new ArrayList<>());
//        for (NavSellOrderSelectJoinOrderResult itemVo : pageResult.getRecords()) {
//            JSONObject itemJson = (JSONObject) JSONObject.toJSON(itemVo);
//            withChildPage.getRecords().add(itemJson);
//            NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
//            paramPo.setPageSize(Integer.MAX_VALUE);
//            List<Long> split = Convert.toList(Long.class, StrUtil.split(itemVo.getJoinId(), ","));
//            paramPo.setSelectedIds(split);
//           itemJson.put("list", withChild ? this.canJoinOrderPageWithChildSearch(paramPo) : this.canJoinOrderPage(paramPo));
//        }
//        return withChildPage;
//      V3版本
        Page<NavSellOrderSelectJoinOrderResult> pageResult = this.selectJoinOrder(param);
        Page<JSONObject> withChildPage = new Page<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal());
        List<NavSellOrderSelectJoinOrderResult> recordList = pageResult.getRecords();
        if (CollUtil.isEmpty(recordList)) {
            return withChildPage;
        }
        List<Long> idList = new ArrayList<>();
        recordList.stream().forEach(f -> CollUtil.addAllIfNotContains(idList, Convert.toList(Long.class, StrUtil.split(f.getJoinId(), ","))));
        NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
        paramPo.setPageSize(Integer.MAX_VALUE);
        paramPo.setSelectedIds(idList);
        Page<NavSellOrderItemVo> canJoinOrderPage = this.canJoinOrderPage(paramPo);
        withChildPage.setRecords(new ArrayList<>());
        for (NavSellOrderSelectJoinOrderResult itemVo : recordList) {
            JSONObject itemJson = (JSONObject) JSONObject.toJSON(itemVo);
            withChildPage.getRecords().add(itemJson);
            List<Long> split = Convert.toList(Long.class, StrUtil.split(itemVo.getJoinId(), ","));
            if (CollUtil.isEmpty(split)) {
                continue;
            }
            Page<NavSellOrderItemVo> itemVoCanJoinOrderPage = new Page<>(1, split.size(), split.size());
            itemVoCanJoinOrderPage.setRecords(canJoinOrderPage.getRecords().stream().filter(f -> split.contains(f.getId())).collect(Collectors.toList()));
            paramPo.setSelectedIds(split);
            paramPo.setFillParts(List.of("platform", "transaction"));
            itemJson.put("list", withChild ? appendWithChild(itemVoCanJoinOrderPage, paramPo.toChildSort("product")) : itemVoCanJoinOrderPage);
        }
        return withChildPage;
    }


    /**
     * 合并检测 :系统自动根据订单的买家信息、收件地址信息判断订单是否支持合并。如同店铺出现买家信息、收货地址一致的订单，订单将被自动打上“可合并订单”处理类型；
     * 勾选需要合并的订单并点击【合并】，订单将合并为一个系统订单。
     * <p>
     * 地址一样，店铺一样，但是客户下了2单，这个时候可以合并节省物流费用（最好加个提醒那些能合并的）
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了合并检测操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void joinTask() {
        try {
            JwtUserInfo currentUser = JwtUserInfo.fromHeader();
            List<NavSellOrder> navSellOrderList = new ArrayList<>();
            NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
            paramPo.setPageSize(Integer.MAX_VALUE);
            List<NavSellOrderSelectJoinOrderResult> joinList = this.selectJoinOrder(paramPo).getRecords();
            if (CollUtil.isEmpty(joinList)) {
                return;
            }
            for (NavSellOrderSelectJoinOrderResult joinItem : joinList) {
                List<String> groupValue = StrUtil.split(joinItem.getJoinId(), ",");
                if (CollUtil.isEmpty(groupValue) && CollUtil.size(groupValue) < 2) {
                    continue;
                }
                List<NavSellOrder> groupValueList = this.list(Wrappers.<NavSellOrder>lambdaQuery().in(NavSellOrder::getId, groupValue));
                //0101 每一组绑定
                for (NavSellOrder groupValueItem : groupValueList) {
                    groupValueItem.setTag(tagHandler(groupValueItem.getTag(), "8"));  //订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
                    groupValueItem.setLastUpdateTime(new Date());
                    //如果存在当前用户
                    if (currentUser != null) {
                        groupValueItem.setLastUpdateUser(currentUser.getUserId());
                    }
                }
                navSellOrderList.addAll(groupValueList);

            }
            if (CollUtil.isEmpty(navSellOrderList)) {
                return;
            }
            //02 更新
            this.updateBatchById(navSellOrderList);
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }

    }


    /**
     * 合并 :系统自动根据订单的买家信息、收件地址信息判断订单是否支持合并。如同店铺出现买家信息、收货地址一致的订单，订单将被自动打上“可合并订单”处理类型；
     * 勾选需要合并的订单并点击【合并】，订单将合并为一个系统订单。
     * <p>
     * 地址一样，店铺一样，但是客户下了2单，这个时候可以合并节省物流费用（最好加个提醒那些能合并的）
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了合并操作")
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void join(List<Long> idList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(idList), "参数异常!");
        try {
            //01 处理
            NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
            paramPo.setSelectedIds(idList);
            paramPo.setPageSize(Integer.MAX_VALUE);
            List<NavSellOrderSelectJoinOrderResult> joinList = this.selectJoinOrder(paramPo).getRecords();
            Assert.isTrue(CollUtil.isNotEmpty(joinList), "不存在需要合并的订单!");
            List<Long> deleteIds = new ArrayList<>();
            for (NavSellOrderSelectJoinOrderResult record : joinList) {
                //02 删除原始的订单
                List<Long> split = Convert.toList(Long.class, StrUtil.split(record.getJoinId(), ","));
                CollUtil.addAll(deleteIds, split);
                //03 合并的组订单处理
                List<NavSellOrderVo> listVo = this.getVoByIdList(split, true);
                for (NavSellOrderVo vo : listVo) {
                    vo.setTransaction(null);
                    vo.setDeclare(null);
                }
                NavSellOrderVo insertNavSellOrder = this.joinHandler(listVo);
                insertNavSellOrder.setOriginalOrderId(record.getJoinOrderId());
                //04 保存合并后订单信息
                this.create(insertNavSellOrder);
            }
            if (CollUtil.isNotEmpty(deleteIds)) {
                //05 删除
                super.batchDelete(deleteIds);
            }
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 插入合并后订单信息处理
     *
     * @param joinVo
     */
    @Transactional(rollbackFor = Exception.class)
    public NavSellOrderVo joinHandler(List<NavSellOrderVo> joinVo) throws Exception {
        //01取其中第一条创建新订单
        NavSellOrderVo entity = BeanUtil.copyProperties(CollUtil.getFirst(joinVo), NavSellOrderVo.class, this.getIgnoreProperties());
        entity.setProduct(CollUtil.newArrayList());
        entity.setPlatform(CollUtil.newArrayList());
        for (NavSellOrderVo navSellOrderVo : joinVo) {
            //02物流预估等处理
            Assert.isTrue(CollUtil.isNotEmpty(navSellOrderVo.getPlatform()), "订单平台数据不存在,请检查!");
            Assert.isTrue(CollUtil.isNotEmpty(navSellOrderVo.getProduct()), "订单平台数据不存在,请检查!");
            for (NavSellOrderPlatformItemVo navSellOrderPlatformItemVo : navSellOrderVo.getPlatform()) {
                CollUtil.addIfAbsent(entity.getPlatform(), BeanUtil.copyProperties(navSellOrderPlatformItemVo, NavSellOrderPlatformItemVo.class, this.getIgnoreProperties()));
            }
            for (NavSellOrderDetailItemVo navSellOrderDetailItemVo : navSellOrderVo.getProduct()) {
                CollUtil.addIfAbsent(entity.getProduct(), BeanUtil.copyProperties(navSellOrderDetailItemVo, NavSellOrderDetailItemVo.class, this.getIgnoreProperties()));
            }
        }
        entity.setTag(tagHandler(entity.getTag(), "9", "8"));//订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
        entity.setSplitType("2");     //拆分订单类型 1:原始单 2:合并单 3:拆分单
        return entity;
    }


    /**
     * 拆分检测 :买家一个订单下了2个店铺的，发货仓库不一样需要拆分发货（提示那些需要拆分的订单）
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了拆分检测操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void splitTask() {
        try {
            NavSellOrderSearchParamPo paramPo = new NavSellOrderSearchParamPo();
            paramPo.setPageSize(Integer.MAX_VALUE);
            List<NavSellOrderSelectSplitOrderResult> splitList = this.selectSplitOrder(paramPo).getRecords();
            if (CollUtil.isEmpty(splitList)) {
                return;
            }
            List<NavSellOrderVo> list = this.getVoByIdList(splitList.stream().map(m -> m.getId()).collect(Collectors.toList()), false);
            for (NavSellOrder item : list) {
                item.setTag(tagHandler(item.getTag(), "21"));//订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                item.setLastUpdateTime(new Date());
                //如果存在当前用户
                if (currentUser != null) {
                    item.setLastUpdateUser(currentUser.getUserId());
                }
            }
            //02 更新
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }


    }


    /**
     * 拆分 :如果用户遇到同一订单中部分商品暂时不发货，或出于运费经济配置的考虑，需要拆分包裹发货，可以操作订单拆分；
     * 勾选需要拆分的订单，点击【拆分订单】，在弹出框中，设置从原单拆分出去的商品数量，点击【拆分预览】，将可以看到订单将被拆分出的子订单的商品分布，确认无误后点击【确认】，即可完成拆分。
     * <p>
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了拆分操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void split(Long id, List<List<NavSellOrderDetailItemVo>> splitList) {
        Assert.isTrue(ObjUtil.isNotEmpty(id), "参数异常!");
        Assert.isTrue(CollUtil.isNotEmpty(splitList), "参数异常!");
        try {
            NavSellOrderVo entity = super.getVoById(id);
            //Assert.isTrue(CollUtil.safeContains(CollUtil.newArrayList("Walmart", "Shein"), CollUtil.getFirst(entity.getPlatform()).getPlatform()), "校验异常,该平台不支持拆单!");
            Assert.isTrue(CollUtil.safeContains(CollUtil.newArrayList("Walmart", "Shein"), CollUtil.getFirst(entity.getPlatform()).getPlatform()), "校验异常,该平台不支持拆单!");
            Assert.isTrue(CollUtil.safeContains(CollUtil.newArrayList("1"), entity.getStatus()), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
            //01 处理拆分
            List<NavSellOrderVo> navSellOrderVoList = this.splitHandler(entity, splitList);
            for (NavSellOrderVo navSellOrderVo : navSellOrderVoList) {
                navSellOrderVo.setOrderId(null);
                navSellOrderVo.setOriginalOrderId(entity.getOrderId());
                this.create(navSellOrderVo);
            }
            //02删除原单
            this.batchDelete(CollUtil.newArrayList(id));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 订单拆分处理
     *
     * @param entity
     * @param splitList
     */
    @Transactional(rollbackFor = Exception.class)
    public List<NavSellOrderVo> splitHandler(NavSellOrderVo entity, List<List<NavSellOrderDetailItemVo>> splitList) throws Exception {
        if (ObjUtil.isEmpty(entity) || CollUtil.isEmpty(splitList)) {
            return null;
        }
        Assert.isTrue(CollUtil.size(splitList) > 1, "拆单数量必须大于1");
        Assert.isTrue(CollUtil.isNotEmpty(entity.getPlatform()), "订单平台数据不存在,请检查!");
        Assert.isTrue(CollUtil.isNotEmpty(entity.getProduct()), "订单平台数据不存在,请检查!");
        BigDecimal earlyQuantity = NumberUtil.add(entity.getProduct().stream().map(NavSellOrderDetailItemVo::getQuantity).toArray(Integer[]::new));
        List<NavSellOrderDetailItemVo> originalList = new ArrayList<>();
        splitList.forEach(item -> CollUtil.addAll(originalList, item));
        BigDecimal splitQuantity = NumberUtil.add(originalList.stream().map(NavSellOrderDetailItemVo::getQuantity).toArray(Integer[]::new));
        Assert.isTrue(NumberUtil.isGreaterOrEqual(earlyQuantity, splitQuantity), "拆分产品总数量大于原始产品总数量,请检查!");
        List<NavSellOrderDetailItemVo> productTempList = new ArrayList<>();
        List<NavSellOrderVo> navSellOrderVoList = new ArrayList<>();
        //按分摊占比处理所有产品
        for (List<NavSellOrderDetailItemVo> productList : splitList) {
            NavSellOrderVo navSellOrderVo = BeanUtil.copyProperties(entity, NavSellOrderVo.class, getIgnoreProperties());
            for (NavSellOrderDetailItemVo vo : productList) {
                //分摊占比 : 拆分数量/原商品数量
                NavSellOrderDetailItemVo earlyEntity = CollUtil.findOne(entity.getProduct(), f -> NumberUtil.equals(f.getId(), vo.getId()));
                Assert.isTrue(ObjUtil.isAllNotEmpty(earlyEntity), "被拆分产品不存在,请联系管理员!");

                Assert.isTrue(NumberUtil.nullToZero(vo.getQuantity()) > 0, "被拆分产品{}的数量包含零,请检查!", earlyEntity.getProductIdName());
                Assert.isTrue(NumberUtil.nullToZero(earlyEntity.getQuantity()) > 0, "拆分产品{}的数量包含零,请检查!", vo.getProductIdName());
                Assert.isTrue(NumberUtil.nullToZero(earlyEntity.getQuantity()) >= NumberUtil.nullToZero(vo.getQuantity()), "拆分产品{}数量大于原始产品数量,请检查!", vo.getProductIdName());

                BigDecimal splitWeight = NumberUtil.div(vo.getQuantity(), earlyEntity.getQuantity(), round * 3);

                vo.setTax(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getTax()), round));//   客付税费
                vo.setTip(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getTip()), round));//     小费
                vo.setDiscount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getDiscount()), round));//   折扣
                vo.setAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getAmount()), round));//   商品金额
                vo.setThinkDeliveryCost(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getThinkDeliveryCost()), round));//   预估出库成本
                vo.setDeliveryThinkFreight(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getDeliveryThinkFreight()), round));//   预估运费
                vo.setDeliveryRealFreight(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getDeliveryRealFreight()), round));//   客付运费
                vo.setTransactionCost(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getTransactionCost()), round));//   交易费
                vo.setOtherAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getOtherAmount()), round));//   平台其他费
                vo.setCgPriceAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getCgPriceAmount()), round));//   采购成本
                vo.setStockAostAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getStockAostAmount()), round));//    库存明细成本
                vo.setWmsOutboundCostAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getWmsOutboundCostAmount()), round));//    实际出库成本
                vo.setCodAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getCodAmount()), round));//    COD费用
                vo.setWmsShippingPriceAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getWmsShippingPriceAmount()), round));//    实际运费
                vo.setGiftWrapAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getGiftWrapAmount()), round));//    礼品包装费
                vo.setSaleTax(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getSaleTax()), round));//    销售税
                vo.setPointsGrantedAmount(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getPointsGrantedAmount()), round));//    积分成本
                vo.setOtherFee(NumberUtil.round(NumberUtil.mul(splitWeight, vo.getOtherFee()), round));//    其他费用
            }
            CollUtil.addAll(productTempList, productList);
            navSellOrderVo.setProduct(productList);
            navSellOrderVo.setTag(tagHandler(entity.getTag(), "22", "21"));//订单标签 1:待人工审核 2:留言处理 3:地址错误 4:商品未配对 5:黑名单 6:未分配仓库 7:未分配物流 8:可合并订单 9:合并订单 10:物流下单失败 11:超时未发货 12:买家取消订单 13:其他 14:买家申请取消 15:仓库物流不匹配 16:第三方作废 17:第三方仓商品未配对 18:第三方仓未开启/第三方仓发货单暂未创建 19:审核失败 20:审核超时请重试 21:可拆分订单 22:拆分订单 23:转FBA配送 24:留言已处理 25:缺货
            navSellOrderVo.setSplitType("3");    //拆分订单类型 1:原始单 2:合并单 3:拆分单
            navSellOrderVoList.add(navSellOrderVo);
        }
        //原订单交易信息
        NavSellOrderTransactionItemVo allTransaction = this.getTransaction(entity.getTransaction());
        //除尾插外交易信息
        NavSellOrderTransactionItemVo commonTransaction = this.getTransaction(this.calcTransaction(CollUtil.sub(productTempList, 0, CollUtil.size(productTempList) - 1), null));
        //处理尾插
        NavSellOrderDetailItemVo tail = CollUtil.getLast(productTempList);
        tail.setTip(NumberUtil.sub(allTransaction.getTip(), commonTransaction.getTip()));//     小费
        tail.setDiscount(NumberUtil.sub(allTransaction.getDiscount(), commonTransaction.getDiscount()));//   折扣
        tail.setAmount(NumberUtil.sub(allTransaction.getAmount(), commonTransaction.getAmount()));//   商品金额
        tail.setThinkDeliveryCost(NumberUtil.sub(allTransaction.getThinkDeliveryCost(), commonTransaction.getThinkDeliveryCost()));//   预估出库成本
        tail.setDeliveryThinkFreight(NumberUtil.sub(allTransaction.getDeliveryThinkFreight(), commonTransaction.getDeliveryThinkFreight()));//   预估运费
        tail.setDeliveryRealFreight(NumberUtil.sub(allTransaction.getDeliveryRealFreight(), commonTransaction.getDeliveryRealFreight()));//   客付运费
        tail.setTransactionCost(NumberUtil.sub(allTransaction.getTransactionCost(), commonTransaction.getTransactionCost()));//   交易费
        tail.setOtherAmount(NumberUtil.sub(allTransaction.getOtherAmount(), commonTransaction.getOtherAmount()));//   平台其他费
        tail.setCgPriceAmount(NumberUtil.sub(allTransaction.getCgPriceAmount(), commonTransaction.getCgPriceAmount()));//   采购成本
        tail.setStockAostAmount(NumberUtil.sub(allTransaction.getStockAostAmount(), commonTransaction.getStockAostAmount()));//    库存明细成本
        tail.setWmsOutboundCostAmount(NumberUtil.sub(allTransaction.getWmsOutboundCostAmount(), commonTransaction.getWmsOutboundCostAmount()));//    实际出库成本
        tail.setCodAmount(NumberUtil.sub(allTransaction.getCodAmount(), commonTransaction.getCodAmount()));//    COD费用
        tail.setWmsShippingPriceAmount(NumberUtil.sub(allTransaction.getWmsShippingPriceAmount(), commonTransaction.getWmsShippingPriceAmount()));//    实际运费
        tail.setGiftWrapAmount(NumberUtil.sub(allTransaction.getGiftWrapAmount(), commonTransaction.getGiftWrapAmount()));//    礼品包装费
        tail.setSaleTax(NumberUtil.sub(allTransaction.getSaleTax(), commonTransaction.getSaleTax()));//    销售税
        tail.setPointsGrantedAmount(NumberUtil.sub(allTransaction.getPointsGrantedAmount(), commonTransaction.getPointsGrantedAmount()));//    积分成本
        tail.setOtherFee(NumberUtil.sub(allTransaction.getOtherFee(), commonTransaction.getOtherFee()));//    其他费用
        return navSellOrderVoList;
    }

    /**
     * 客服备注 :用户在系统中为订单添加的备注信息，添加/编辑后，仓库在对应订单中可查看到该备注，用于订单特殊信息传递给仓库人员，或做订单备注记录；
     * <p>
     * 修改订单客服备注，备注订单用什么卡片，让仓库配货
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了客服备注操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customRecordRemark(CustomNavSellOrderRecordRemarkActionVo vo) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(vo.getIdList()), "请选择订单!");
        Assert.isTrue(StrUtil.isNotBlank(vo.getRemark()), "备注为空!");
        if (ObjUtil.isEmpty(vo.getReplace())) {
            vo.setReplace(false);
        }
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(vo.getIdList(), false);
            for (NavSellOrderVo item : list) {
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                if (!vo.getReplace()) {
                    item.setRemark(StrUtil.concat(true, item.getRemark(), " ", vo.getRemark()));
                } else {
                    item.setRemark(StrUtil.concat(true, vo.getRemark()));
                }
                item.setLastUpdateTime(new Date());
                if (currentUser != null) {
                    item.setLastUpdateUser(currentUser.getUserId());
                }
            }
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 创建并提交售后订单
     *
     * @param model
     * @return
     * @throws Exception
     */
    @DataActivity(action = SysDataActivityAction.Other, message = "%s执行了创建并提交售后订单操作")
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public Long customCreateAndSubmitAfterSellOrder(NavAfterSellOrderVo model) throws Exception {
        Assert.isTrue(ObjUtil.isNotEmpty(model), "参数异常!");
        try {
            Assert.isTrue(ObjUtil.isAllNotEmpty(model, model.getNavSellOrderId()), "参数异常!");
            Assert.isTrue(ObjUtil.isAllNotEmpty(model.getDetail()), "售后信息参数异常!");
            Assert.isTrue(!hasTagHandler(model.getTag(), "23"), "校验异常,转FBA发货订单不支持创建售后!");
            Assert.isTrue(!StrUtil.equals("5", model.getStatus()), "校验异常,平台订单不支持创建售后!");
            //默认信息
            NavSellOrder byId = this.getById(model.getNavSellOrderId());
            if (StrUtil.isBlank(model.getSource())) {
                model.setSource(byId.getSource());
            }
            if (StrUtil.isBlank(model.getDeliveryWaybillId())) {
                model.setDeliveryWaybillId(byId.getDeliveryWaybillId());
            }
            if (StrUtil.isBlank(model.getDeliveryTrackId())) {
                model.setDeliveryTrackId(byId.getDeliveryTrackId());
            }
            if (StrUtil.equals("1", model.getType()) && StrUtil.equals("1", model.getCut())) {//1:仅退款 2:补发
                Assert.isTrue(CollUtil.safeContains(CollUtil.newArrayList("3"), byId.getStatus()), "仅退款截单的订单必须为待发货或发货中!");
            }
            //重复生成检测
            final List<NavAfterSellOrder> repeatList = navAfterSellOrderService.list(Wrappers.<NavAfterSellOrder>lambdaQuery().eq(NavAfterSellOrder::getNavSellOrderId, model.getNavSellOrderId()).ne(NavAfterSellOrder::getStatus, "-1"));
            Assert.isTrue(CollUtil.isEmpty(repeatList), "重复生成售后订单,单号:{}", repeatList.stream().map(m -> m.getOrderId()).collect(Collectors.joining(",")));
            Long id = navAfterSellOrderService.create(model);
            navAfterSellOrderService.submit(CollUtil.newArrayList(id));
            return id;
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 快捷编辑
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了快捷编辑操作"
    )
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customQuickEdit(CustomNavSellOrderQuickEditActionVo vo) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(vo.getIdList()), "请选择订单!");
        Assert.isTrue(StrUtil.isAllNotBlank(vo.getLogisticsAddressActFill(), vo.getReloadPari()), "参数为空!");
        String logisticsAddressActFill = Convert.toStr(vo.getReloadPari(), "0");
        Boolean reloadPari = Convert.toBool(vo.getReloadPari(), false);
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(vo.getIdList(), true);
            for (NavSellOrderVo item : list) {
                JwtUserInfo currentUser = JwtUserInfo.fromHeader();
                this.logisticsAddressActFill(item, logisticsAddressActFill);
                if (reloadPari) {
                    this.update(item);
                }
                item.setLastUpdateTime(new Date());
                if (currentUser != null) {
                    item.setLastUpdateUser(currentUser.getUserId());
                }
            }
            this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    /**
     * 更新报关信息
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了更新报关信息操作"
    )
    @Transactional(rollbackFor = Exception.class)
    public void customDeclareToProduct(CustomNavSellOrderDeclareToProductActionVo vo) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(vo.getList()) && ObjUtil.isNotEmpty(vo.getId()), "参数为空!");
        Assert.isTrue(vo.getList().stream().allMatch(a -> ObjUtil.isAllNotEmpty(a.getChineseName(), a.getEnglishName(), a.getSku(), a.getCustomsCode(), a.getProductId())), "必填参数缺失!");
        Assert.isTrue(vo.getList().stream().allMatch(a -> NumberUtil.isGreater(a.getPackingWeight(), BigDecimal.ZERO)), "重量必须大于0!");
        Assert.isTrue(vo.getList().stream().allMatch(a -> NumberUtil.isGreater(Convert.toBigDecimal(a.getQuantity()), BigDecimal.ZERO)), "数量必须大于0!");
        try {
            List<Product> productList = new ArrayList<>();
            List<NavSellOrderDeclare> declareList = vo.getList();
            for (NavSellOrderDeclare item : declareList) {
                ProductVo product = productService.getVoById(item.getProductId());
                product.setPackingWeight(item.getPackingWeight());
                product.setCustomsCharges(item.getCustomsCharges());
                product.setChineseName(item.getChineseName());
                product.setEnglishName(item.getEnglishName());
                product.setCustomsCode(item.getCustomsCode());
                CollUtil.addIfAbsent(productList, product);
            }
            productService.updateBatchById(productList);
            navSellOrderDeclareService.updateBatchById(declareList);
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    /**
     * 更新报关信息批量
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了批量更新报关信息操作"
    )
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void customDeclareToProductList(List<CustomNavSellOrderDeclareToProductActionVo> voList) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(voList), "参数为空!");
        for (CustomNavSellOrderDeclareToProductActionVo vo : voList) {
            this.customDeclareToProduct(vo);
        }
    }


/**************************************公用方法******************************************/

    /**
     * 拷贝忽略的字段
     *
     * @param ignoreProperties
     * @return
     */
    public String[] getIgnoreProperties(String... ignoreProperties) {
        String[] array = Arrays.stream(ReflectUtil.getFields(SysBase.class)).map(m -> ReflectUtil.getFieldName(m)).toArray(String[]::new);
        return ArrayUtil.append(ignoreProperties, array);
    }

    /**
     * 更新订单管理状态
     *
     * @param list
     * @param status // 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
     */
    @Transactional(rollbackFor = Exception.class)
    public void changeNavSellOrder(List<NavSellOrderVo> list, String status, String tag, String removeTag) {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();

        //解冻结外判定冻结操作
        if (!CollUtil.safeContains(CollUtil.newArrayList("1", "-1", null), status)) {
            Assert.isTrue(list.stream().allMatch(a -> !CollUtil.safeContains(CollUtil.newArrayList("-2"), a.getStatus())), "校验异常,包含已冻结订单!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结
        }
        for (NavSellOrderVo entity : list) {
            // 获取简单状态
            String rawSimpleStatus = entity.getStatus();
            if (StrUtil.isNotBlank(status)) {
                entity.setStatus(status);
            }
            if (ObjUtil.isNotEmpty(tag) || ObjUtil.isNotEmpty(removeTag)) {
                entity.setTag(this.tagHandler(entity.getTag(), tag, removeTag));
            }
            entity.setLastUpdateTime(new Date());
            //如果存在当前用户
            if (currentUser != null) {
                entity.setLastUpdateUser(currentUser.getUserId());
            }
            // 简单流程状态更新
            if (status != null) {
                simpleStatusService.afterUpdate(
                        "NavSellOrder",
                        currentUser == null ? "" : currentUser.getDisplayName(),
                        entity.getId(),
                        rawSimpleStatus,
                        status
                );
            }
        }
        this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
    }

    @Transactional(rollbackFor = Exception.class)
    public void changeNavSellOrderStatus(List<NavSellOrderVo> list, String status) {
        this.changeNavSellOrder(list, status, null, null);
    }


    @Transactional(rollbackFor = Exception.class)
    public void changeNavSellOrderTag(List<NavSellOrderVo> list, String tag, String removeTag) {
        this.changeNavSellOrder(list, null, tag, removeTag);
    }

    /**
     * 更新销售出库单状态
     *
     * @param list
     * @param status 1:物流下单 2:发货中 3:已发货 -1:已取消
     */
    @Transactional(rollbackFor = Exception.class)
    public void changeWmsOrderStatus(List<NavSellOrderVo> list, String status) {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        Assert.isTrue(CollUtil.isNotEmpty(list) && CollUtil.size(list) < 100, "选择销售出库单量应在1~100之间!");
        //02 更新发货单状态
        List<WmsOrder> wmsOrderList = wmsOrderService.list(Wrappers.<WmsOrder>lambdaQuery().in(WmsOrder::getOrderNumber, list.stream().map(m -> m.getOrderId()).collect(Collectors.toList())));
        if (CollUtil.isEmpty(wmsOrderList)) {
            return;
        }
        for (WmsOrder wmsOrder : wmsOrderList) {
            NavSellOrder navSellOrder = CollUtil.findOne(list, item -> item.getOrderId().equals(wmsOrder.getOrderNumber()));
            if (ObjUtil.isEmpty(navSellOrder)) {
                wmsOrder.setWaveOrder(null);//波次号
                wmsOrder.setTagNames(this.getTagHandler(navSellOrder.getTag()));//标签
                wmsOrder.setOrderCustomerServiceNotes(navSellOrder.getRemark());//客服备注
                wmsOrder.setStockDeliveredAt(null);//库存流水出库时间
                wmsOrder.setIsCheck(navSellOrder.getIsTest());//是否验货
                wmsOrder.setIsWeigh(navSellOrder.getIsWeigh());//是否称重
                wmsOrder.setIsSurfacePrint(navSellOrder.getPrintFaceStatus());//面单是否打印
                wmsOrder.setIsorderPrint(navSellOrder.getPrintOrderStatus());//订单是否打印
                wmsOrder.setPicker(null);//拣货人
                wmsOrder.setDeliveredAt(null);//出库时间
                wmsOrder.setProcessSn(null);//加工单号
                wmsOrder.setBatchNo(null);//批次号
                wmsOrder.setSurfaceFile(null);//面单文件
            }
            wmsOrder.setStatus(status);
            wmsOrder.setLastUpdateTime(new Date());
            //如果存在当前用户
            if (currentUser != null) {
                wmsOrder.setLastUpdateUser(currentUser.getUserId());
            }
        }
        wmsOrderService.updateBatchById(wmsOrderList);
    }

    /**
     * 删除销售出库单
     *
     * @param list
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteWmsOrder(List<NavSellOrderVo> list) {
        //01 更新发货单状态
        List<WmsOrder> wmsOrderList = wmsOrderService.list(Wrappers.<WmsOrder>lambdaQuery().in(WmsOrder::getOrderNumber, list.stream().map(m -> m.getOrderId()).collect(Collectors.toList())));
        if (CollUtil.isEmpty(wmsOrderList)) {
            return;
        }
        wmsOrderService.removeBatchByIds(wmsOrderList);
    }


    /**
     * 更新标发状态
     *
     * @param list
     * @param issuStatus
     */
    @Transactional(rollbackFor = Exception.class)
    public void changeIssuOrderIssuStatus(List<NavSellOrderVo> list, String issuStatus, String onlineStatus) {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        for (NavSellOrderVo entity : list) {
            // 获取简单状态
            String rawSimpleStatus = entity.getStatus();
            entity.setIssuStatus(issuStatus);
            entity.setOnlineStatus(onlineStatus);
            entity.setLastUpdateTime(new Date());
            //如果存在当前用户
            if (currentUser != null) {
                entity.setLastUpdateUser(currentUser.getUserId());
            }
            // 简单流程状态更新
            if (issuStatus != null) {
                simpleStatusService.afterUpdate(
                        "IssuOrder",
                        currentUser == null ? "" : currentUser.getDisplayName(),
                        entity.getId(),
                        rawSimpleStatus,
                        issuStatus
                );
            }
        }
        this.updateBatchById(BeanUtil.copyToList(list, NavSellOrder.class));
    }


    /**
     * 包含tag
     *
     * @param tag
     */
    public boolean hasTagHandler(String tag, String hasTag) {
        if (StrUtil.isNotBlank(tag)) {
            return CollUtil.safeContains(StrUtil.split(tag, ","), hasTag);
        }
        return false;
    }

    /**
     * 获取tag名称
     *
     * @param tag
     */
    public String getTagHandler(String tag) {
        String tagNames = null;
        if (StrUtil.isNotBlank(tag)) {
            List<SysDictAllItem> tagItems = SpringUtil.getBean(SysDictService.class).getDictItems("SCM00142");
            final List<String> tagValues = Arrays.stream(tag.split(",")).filter(StringUtils::hasText).collect(Collectors.toList());
            tagNames = tagItems.stream().filter(i -> tagValues.contains(i.getItemValue())).map(SysDictAllItem::getItemText).collect(Collectors.joining(","));
        }
        return tagNames;
    }

    /**
     * tag多选处理并移除部分元素
     *
     * @param tag
     * @return
     */
    public String tagHandler(String tag, String tagNew, String removeTag) {
        String finalTag = this.tagHandler(tag, tagNew);
        return StrUtil.join(",", CollUtil.removeAny(StrUtil.split(finalTag, ","), StrUtil.splitToArray(removeTag, ",")));
    }

    /**
     * tag多选处理
     *
     * @param tag
     * @return
     */
    public String tagHandler(String tag, String tagNew) {
        if (StrUtil.isAllEmpty(tag, tagNew)) {
            return null;
        }
        if (StrUtil.isBlank(tag)) {
            tag = null;
        }
        if (StrUtil.isBlank(tagNew)) {
            tagNew = null;
        }
//        List<String> tagList = StrUtil.split(tag, ",");
//        List<String> tagNewList = StrUtil.split(tagNew, ",");
//        List<String> distinct = CollUtil.distinct(CollUtil.addAll(tagNewList, tagList));
        List<String> tagList = StrUtil.split(tag, ",");
        List<String> tagNewList = StrUtil.split(tagNew, ",");
        List<String> distinct = CollUtil.distinct(CollUtil.unionAll(tagList, tagNewList));
        return CollUtil.join(distinct, ",");
    }

//    public static void main(String[] args) {
//        NavSellOrderServiceImpl navSellOrderService = new NavSellOrderServiceImpl();
//        String s = navSellOrderService.tagHandler("1,2,3", "1,2,4", "1,2,12");
//        System.out.println(s);
//
//    }


    /**
     * 计算产品相关
     *
     * @param model
     * @return
     */
    public NavSellOrderVo calcProduct(NavSellOrderVo model) throws Exception {
        List<NavSellOrderDetailItemVo> productList = model.getProduct();
        boolean isPari = true; //是否配对商品
        for (NavSellOrderDetailItemVo item : productList) {
            Assert.isTrue(StrUtil.isNotBlank(item.getMsku()), "MSKU不能为空!");
            Assert.isTrue(ObjUtil.isNotEmpty(item.getShopInfo()), "店铺不能为空!");
            Parilist parilist = SpringUtil.getBean(ParilistServiceImpl.class).getParilist(item.getShopInfo(), item.getMsku());
            if (ObjUtil.isEmpty(parilist)) { // 没有匹配商品
                isPari = false;
            } else {
                ProductVo productVo = productService.getVoById(parilist.getProductId());
                Assert.isTrue(ObjUtil.isNotEmpty(parilist), "产品{}不存在!", parilist.getProductId());
                item.setImg(productVo.getPicUrl());
                item.setProductId(productVo.getId());
                item.setProductIdName(productVo.getName());
                item.setProductName(productVo.getName());
                item.setSku(productVo.getSku());
                item.setThinkDeliveryCost(NumberUtil.mul(productVo.getProcurementCost(), item.getQuantity()));
                item.setChineseName(productVo.getChineseName());
                item.setEnglishName(productVo.getEnglishName());
            }
        }
        model.setTag(this.tagHandler(model.getTag(), "4", isPari ? "4" : null));
        return model;
    }


    /**
     * 计算平台相关
     *
     * @param list
     * @return
     * @throws Exception
     */
    public List<NavSellOrderPlatformItemVo> calcPlatform(Long id, List<NavSellOrderPlatformItemVo> list) {
        Assert.isTrue(CollUtil.isNotEmpty(list), "平台信息参数异常!");
//        if (ObjUtil.isNotEmpty(id)) {
//        SpringUtil.getBean(NavSellOrderPlatformServiceImpl.class).remove(Wrappers.<NavSellOrderPlatform>lambdaQuery().eq(NavSellOrderPlatform::getParentNavSellOrder, id));
//       }
//        for (NavSellOrderPlatformItemVo platform : list) {
//            platform.setId(null);
//            platform.setParentNavSellOrder(null);
//        }
        return CollUtil.distinct(list, NavSellOrderPlatformItemVo::getPlatformOrderId, false);
    }

    /**
     * 计算物流尺寸相关(预估尺寸产品内维护,合并:多个产品也是根据产品管理的长宽高组合绑定的,暂时不做支持)
     *
     * @param entity
     * @return
     * @throws Exception
     */
    public NavSellOrderVo calcDelivery(Long id, NavSellOrderVo entity) throws Exception {
        Assert.isTrue(ObjUtil.isNotEmpty(entity), "订单信息参数异常!");
        List<NavSellOrderDetailItemVo> productList = entity.getProduct();
        Assert.isTrue(CollUtil.isNotEmpty(productList), "订单产品信息错误!");
        List<Product> pList = SpringUtil.getBean(ProductBaseServiceImpl.class).listByIds(productList.stream().map(m -> m.getProductId()).collect(Collectors.toList()));
        if (CollUtil.size(pList) == 1) {
            Product p = CollUtil.getFirst(pList);
            Assert.isTrue(ObjUtil.isNotEmpty(p), "订单产品信息关联错误!");
            entity.setDeliveryThinkSizeLength(p.getBoxLength());//   估算尺寸长
            entity.setDeliveryThinkSizeWidth(p.getBoxWidth());//   估算尺寸宽
            entity.setDeliveryThinkSizeHeight(p.getBoxHeight());//   估算尺寸高

            entity.setDeliveryRealSizeLength(Decimal.ZERO);//   包裹长
            entity.setDeliveryRealSizeWidth(Decimal.ZERO);//   包裹宽
            entity.setDeliveryRealSizeHeight(Decimal.ZERO);//   包裹高
        }
        BigDecimal deliveryThinkWeight = NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getDeliveryThinkWeight).toArray(BigDecimal[]::new));//  订单产品重量
        if (NumberUtil.equals(deliveryThinkWeight, Decimal.ZERO)) {
            deliveryThinkWeight = NumberUtil.add(pList.stream().map(Product::getPackingWeight).toArray(BigDecimal[]::new));
        }
        entity.setDeliveryThinkWeight(deliveryThinkWeight);//  估算重量
        entity.setDeliveryThinkVolume(Decimal.ZERO);//   预估包裹体积
        entity.setDeliveryThinkFeeWeight(deliveryThinkWeight);//   估算计费重
        entity.setDeliveryRealWeight(Decimal.ZERO);//   包裹实重
        entity.setDeliveryRealVolume(Decimal.ZERO);//   包裹体积
        entity.setDeliveryRealFeeWeight(Decimal.ZERO);//   实际计费重
        return entity;
    }


    public List<NavSellOrderTransactionItemVo> calcTransaction(Long
                                                                       id, List<NavSellOrderDetailItemVo> productList, NavSellOrderTransactionItemVo transaction) {
        if (ObjUtil.isNotEmpty(id)) {
            SpringUtil.getBean(NavSellOrderTransactionServiceImpl.class).remove(Wrappers.<NavSellOrderTransaction>lambdaQuery().eq(NavSellOrderTransaction::getParentNavSellOrder, id));
        }
        return this.calcTransaction(productList, transaction);
    }

    /**
     * 根据产品计算交易信息
     *
     * @param productList
     * @return
     * @throws Exception
     */
    public List<NavSellOrderTransactionItemVo> calcTransaction
    (List<NavSellOrderDetailItemVo> productList, NavSellOrderTransactionItemVo transaction) {
        Assert.isTrue(CollUtil.isNotEmpty(productList), "交易信息参数异常!");
        Assert.isTrue(CollUtil.allMatch(productList, a -> NumberUtil.isGreaterOrEqual(Convert.toBigDecimal(a.getAmount(), BigDecimal.ZERO), BigDecimal.ZERO)), "交易信息处理异常,商品金额必须大于等于零!");
        if (ObjUtil.isEmpty(transaction)) {
            transaction = new NavSellOrderTransactionItemVo();
            transaction.setTax(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getTax).toArray(BigDecimal[]::new)));//   客付税费
            transaction.setTip(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getTip).toArray(BigDecimal[]::new)));//     小费
            transaction.setDiscount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getDiscount).toArray(BigDecimal[]::new)));//   折扣
            transaction.setAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getAmount).toArray(BigDecimal[]::new)));//   商品金额
            transaction.setDeliveryThinkFreight(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getDeliveryThinkFreight).toArray(BigDecimal[]::new)));//   预估运费
            transaction.setDeliveryRealFreight(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getDeliveryRealFreight).toArray(BigDecimal[]::new)));//   客付运费
            transaction.setTransactionCost(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getTransactionCost).toArray(BigDecimal[]::new)));//   交易费
            transaction.setOtherAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getOtherAmount).toArray(BigDecimal[]::new)));//   平台其他费
            transaction.setCodAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getCodAmount).toArray(BigDecimal[]::new)));//    COD费用
            transaction.setGiftWrapAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getGiftWrapAmount).toArray(BigDecimal[]::new)));//    礼品包装费
            transaction.setSaleTax(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getSaleTax).toArray(BigDecimal[]::new)));//    销售税
            transaction.setPointsGrantedAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getPointsGrantedAmount).toArray(BigDecimal[]::new)));//    积分成本
        }

        transaction.setThinkDeliveryCost(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getThinkDeliveryCost).toArray(BigDecimal[]::new)));//   预估出库成本
        transaction.setCgPriceAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getCgPriceAmount).toArray(BigDecimal[]::new)));//   采购成本
        transaction.setStockAostAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getStockAostAmount).toArray(BigDecimal[]::new)));//    库存明细成本
        transaction.setWmsOutboundCostAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getWmsOutboundCostAmount).toArray(BigDecimal[]::new)));//    实际出库成本
        transaction.setWmsShippingPriceAmount(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getWmsShippingPriceAmount).toArray(BigDecimal[]::new)));//    实际运费
        transaction.setOtherFee(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getOtherFee).toArray(BigDecimal[]::new)));//    其他费用
        //首先订单总额 = 商品金额+折扣+客付运费+小费
        //订单毛利润 = 订单总额-其他费用-出库成本-物流运费-交易费
        //毛利率=毛利润/销售额
        transaction.setTotalAmount(NumberUtil.sub(NumberUtil.add(transaction.getAmount(), transaction.getDeliveryRealFreight(), transaction.getTip(), transaction.getDiscount(), transaction.getOtherAmount())));
        transaction.setThinkGrossProfit(NumberUtil.sub(transaction.getTotalAmount(), transaction.getThinkDeliveryCost(), transaction.getDeliveryThinkFreight(), transaction.getTax(), transaction.getTransactionCost(), transaction.getOtherFee()));
        transaction.setThinkGrossMargin(NumberUtil.div(transaction.getThinkGrossProfit(), NumberUtil.equals(transaction.getTotalAmount(), BigDecimal.ZERO) ? 1 : transaction.getTotalAmount(), 2));
        return CollUtil.newArrayList(transaction);
    }


    /**
     * 获取交易汇总信息
     *
     * @param list
     * @return
     * @throws Exception
     */
    public NavSellOrderTransactionItemVo getTransaction(List<NavSellOrderTransactionItemVo> list) {
        Assert.isTrue(CollUtil.isNotEmpty(list), "订单交易信息为空!");
        NavSellOrderTransactionItemVo transaction = new NavSellOrderTransactionItemVo();
        transaction.setTax(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getTax).toArray(BigDecimal[]::new)));//   客付税费
        transaction.setTip(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getTip).toArray(BigDecimal[]::new)));//     小费
        transaction.setDiscount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getDiscount).toArray(BigDecimal[]::new)));//   折扣
        transaction.setAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getAmount).toArray(BigDecimal[]::new)));//   商品金额
        transaction.setThinkDeliveryCost(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getThinkDeliveryCost).toArray(BigDecimal[]::new)));//   预估出库成本
        transaction.setDeliveryThinkFreight(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getDeliveryThinkFreight).toArray(BigDecimal[]::new)));//   预估运费
        transaction.setDeliveryRealFreight(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getDeliveryRealFreight).toArray(BigDecimal[]::new)));//   客付运费
        transaction.setTransactionCost(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getTransactionCost).toArray(BigDecimal[]::new)));//   交易费
        transaction.setOtherAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getOtherAmount).toArray(BigDecimal[]::new)));//   平台其他费
        transaction.setCgPriceAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getCgPriceAmount).toArray(BigDecimal[]::new)));//   采购成本
        transaction.setStockAostAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getStockAostAmount).toArray(BigDecimal[]::new)));//    库存明细成本
        transaction.setWmsOutboundCostAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getWmsOutboundCostAmount).toArray(BigDecimal[]::new)));//    实际出库成本
        transaction.setCodAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getCodAmount).toArray(BigDecimal[]::new)));//    COD费用
        transaction.setWmsShippingPriceAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getWmsShippingPriceAmount).toArray(BigDecimal[]::new)));//    实际运费
        transaction.setGiftWrapAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getGiftWrapAmount).toArray(BigDecimal[]::new)));//    礼品包装费
        transaction.setSaleTax(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getSaleTax).toArray(BigDecimal[]::new)));//    销售税
        transaction.setPointsGrantedAmount(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getPointsGrantedAmount).toArray(BigDecimal[]::new)));//    积分成本
        transaction.setOtherFee(NumberUtil.add(list.stream().map(NavSellOrderTransactionItemVo::getOtherFee).toArray(BigDecimal[]::new)));//    其他费用
        transaction.setTotalAmount(NumberUtil.add(transaction.getAmount(), transaction.getDeliveryRealFreight(), transaction.getOtherAmount()));//   订单总额=商品总额+客付运费+其他费用（默认为0）
        transaction.setThinkGrossProfit(NumberUtil.sub(transaction.getTotalAmount(), transaction.getThinkDeliveryCost(), transaction.getDeliveryThinkFreight(), transaction.getTax(), transaction.getTransactionCost()));//    预估毛利润=订单总额-预估出库成本-预估运费-客付税费-交易费
        return transaction;
    }


    /**
     * 根据产品计算报关信息
     *
     * @param productList
     * @return
     * @throws Exception
     */
    public List<NavSellOrderDeclareItemVo> calcDeclare(Long id, List<NavSellOrderDetailItemVo> productList) throws
            Exception {
        Assert.isTrue(CollUtil.isNotEmpty(productList), "报关信息参数异常!");
        // 处理子表字段 报关信息(declare) 对应的对象
        if (ObjUtil.isNotEmpty(id)) {
            NavSellOrderDeclareSearchParamPo declareSearchParam = new NavSellOrderDeclareSearchParamPo();
            declareSearchParam.setParentNavSellOrderInList(CollUtil.newArrayList(id));
            List<Long> declareIdList = SpringUtil.getBean(NavSellOrderDeclareMapper.class).searchIds(declareSearchParam);
            if (!declareIdList.isEmpty()) {
                SpringUtil.getBean(NavSellOrderDeclareService.class).batchDelete(declareIdList);
            }
        }

        List<NavSellOrderDeclareItemVo> list = new ArrayList<>();
        for (NavSellOrderDetailItemVo detail : productList) {
            //一个产品只报一次
            List<Long> idList = list.stream().map(m -> m.getProductId()).collect(Collectors.toList());
            if (CollUtil.safeContains(idList, detail.getProductId())) {
                continue;
            }
            ProductVo p = SpringUtil.getBean(ProductBaseServiceImpl.class).getVoById(detail.getProductId());
            if (ObjUtil.isEmpty(p)) {
                continue;
            }
            //Assert.isTrue(ObjUtil.isNotEmpty(p), "订单产品信息关联错误!");
            NavSellOrderDeclareItemVo vo = BeanUtil.copyProperties(p, NavSellOrderDeclareItemVo.class, this.getIgnoreProperties());
            vo.setParentNavSellOrder(detail.getParentNavSellOrder());
            vo.setParentNavSellOrderOrderId(detail.getParentNavSellOrderOrderId());
            vo.setProductId(detail.getProductId());
            vo.setProductName(detail.getProductName());
            BigDecimal quantity = NumberUtil.add(productList.stream().filter(f -> NumberUtil.equals(f.getProductId(), detail.getProductId())).map(NavSellOrderDetailItemVo::getQuantity).toArray(Integer[]::new));
            vo.setQuantity(Convert.toInt(quantity));
            //如果订单商品没有重量,则用产品重量
            if (NumberUtil.equals(vo.getPackingWeight(), Decimal.ZERO)) {
                vo.setPackingWeight(NumberUtil.round(NumberUtil.mul(p.getPackingWeight(), quantity), round));
            }
            detail.setChineseName(p.getChineseName());
            detail.setEnglishName(p.getEnglishName());
            vo.setCustomsCode(p.getCustomsCode());
            CollUtil.addAll(list, vo);
        }
        return list;
    }


    //订单规则处理
    @Transactional
    public void orderHandler(NavSellOrderVo navSellOrder) {
        List<NavOrderRule> list = this.getNavOrderRuleList();
        //仓库
        this.setUpWarehouse(navSellOrder, list);
        //物流
        this.setUpLogistics(navSellOrder, list);
        //地址
        this.setUpAddress(navSellOrder, list);
        //规则
        this.setUpStandardIssuance(navSellOrder, list);
        //更新
        super.updateById(navSellOrder);
    }

    /**
     * 获取订单规则
     *
     * @return
     */
    public List<NavOrderRule> getNavOrderRuleList() {
        //获取启用规则
        List<NavOrderRule> list = orderRuleService.list(Wrappers.<NavOrderRule>query().lambda().eq(NavOrderRule::getStatus, "1"));
        return list;
    }

    //设置仓库规则
    private NavOrderRule setUpWarehouse(NavSellOrderVo navSellOrder, List<NavOrderRule> orderRulelist) {
        if (ObjUtil.isNotEmpty(navSellOrder.getDeliveryWarehouse())) {
            this.isHaveStock(navSellOrder.getDeliveryWarehouse(), "3", navSellOrder.getProduct()); //3:SKU+空
            return null;
        }
        //筛选仓库的规则
        List<NavOrderRule> collect = orderRulelist.stream().filter(f -> StrUtil.equalsIgnoreCase("3", f.getType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        //匹配
        List<NavOrderRule> orderRuleList = this.getNavOrderRule(collect, navSellOrder);
        if (CollUtil.isEmpty(orderRuleList)) {
            return null;
        }
        NavOrderRule orderRule = orderRuleList.get(0);
        //设置订单仓库
        setWarehouse(orderRule, navSellOrder);
        return orderRule;
    }

    //设置物流规则
    private NavOrderRule setUpLogistics(NavSellOrderVo navSellOrder, List<NavOrderRule> orderRulelist) {
        if (ObjUtil.isNotEmpty(navSellOrder.getDeliveryLogisticsChannel())) {
            return null;
        }
        //筛选仓库的规则
        List<NavOrderRule> collect = orderRulelist.stream().filter(f -> StrUtil.equalsIgnoreCase("4", f.getType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        //规则基础信息匹配
        List<NavOrderRule> orderRuleList = this.getNavOrderRule(collect, navSellOrder);
        if (CollUtil.isEmpty(orderRuleList)) {
            return null;
        }
        NavOrderRule orderRule = orderRuleList.get(0);
        //设置订单物流
        setLogistics(orderRule, navSellOrder);
        return orderRule;
    }

    //设置地址规则
    private NavOrderRule setUpAddress(NavSellOrderVo navSellOrder, List<NavOrderRule> orderRulelist) {
        //筛选仓库的规则
        List<NavOrderRule> collect = orderRulelist.stream().filter(f -> StrUtil.equalsIgnoreCase("5", f.getType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        //规则基础信息匹配
        List<NavOrderRule> orderRuleList = this.getNavOrderRule(collect, navSellOrder);
        if (CollUtil.isEmpty(orderRuleList)) {
            return null;
        }
        NavOrderRule orderRule = orderRuleList.get(0);
        //设置订单地址
        this.setAddress(orderRule, navSellOrder);
        return orderRule;
    }


    //设置标发规则
    private NavOrderRule setUpStandardIssuance(NavSellOrderVo navSellOrder, List<NavOrderRule> orderRulelist) {
        //获取启用规则
        List<NavOrderRule> collect = orderRulelist.stream().filter(f -> StrUtil.equalsIgnoreCase("7", f.getType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        //规则基础信息匹配
        List<NavOrderRule> orderRuleList = this.getNavOrderRule(collect, navSellOrder);
        if (CollUtil.isEmpty(orderRuleList)) {
            return null;
        }
        NavOrderRule orderRule = orderRuleList.get(0);
        if (ObjUtil.isNotEmpty(orderRule) && StrUtil.equals(orderRule.getIssuActRules(), "1")) {   // 1:自动标发 2:不标发
            navSellOrder.setIssuActRules(orderRule.getIssuActRules());
        } else if (ObjUtil.isNotEmpty(orderRule) && StrUtil.equals(orderRule.getIssuActRules(), "2")) {   // 1:自动标发 2:不标发
            navSellOrder.setIssuActRules(orderRule.getIssuActRules());
        } else {
            navSellOrder.setIssuActRules("0");
        }
        return orderRule;
    }

    private void setAddress(NavOrderRule orderRule, NavSellOrderVo navSellOrder) {
        //省州、城市为空填充
        String logisticsAddressActFill = Convert.toStr(orderRule.getLogisticsAddressActFill()); //1:若收货地址城市为空，使用省/州信息进行填充 2:若收货地址省/州为空，使用城市信息进行填充
        //订单规则省州全称/简称替换
        String logisticsAddressActSelectQJ = Convert.toStr(orderRule.getLogisticsAddressActSelectQJ()); //1:全称替换为简称 2:简称替换为全称
        //门牌号解析1
        String logisticsAddressActHouseNoAnalysis1 = orderRule.getLogisticsAddressActHouseNoAnalysis1();
        String logisticsAddressActHouseNoAnalysis2 = orderRule.getLogisticsAddressActHouseNoAnalysis2();
        String logisticsAddressActHouseNoAnalysis3 = orderRule.getLogisticsAddressActHouseNoAnalysis3();
        //电话号码简化1
        String addressActPhoneSimplify1 = orderRule.getAddressActPhoneSimplify1();
        String addressActPhoneSimplify2 = orderRule.getAddressActPhoneSimplify2();
        String addressActPhoneSimplify3 = orderRule.getAddressActPhoneSimplify3();
        String addressActPhoneSimplify4 = orderRule.getAddressActPhoneSimplify4();

        String addressActPostHandle1 = orderRule.getAddressActPostHandle1();
        String addressActPostHandle2 = orderRule.getAddressActPostHandle2();
        this.logisticsAddressActFill(navSellOrder, logisticsAddressActFill);
        this.logisticsAddressActSelectQJ(navSellOrder, logisticsAddressActSelectQJ);
    }

    /**
     * //全称替换为简称 2:简称替换为全称
     *
     * @param navSellOrder
     * @param logisticsAddressActSelectQJ
     */
    public void logisticsAddressActSelectQJ(NavSellOrderVo navSellOrder, String logisticsAddressActSelectQJ) {
        if (StrUtil.equals("1", logisticsAddressActSelectQJ)) {
            NavLogisticsMapping selectOneMapping = logisticsMappingService.getOne(Wrappers.<NavLogisticsMapping>lambdaQuery().eq(NavLogisticsMapping::getProvinceFullName, navSellOrder.getDeliveryProvince()), false);
            if (ObjUtil.isNotEmpty(selectOneMapping)) {
                navSellOrder.setDeliveryProvince(selectOneMapping.getProvinceSimpleName());
            }
        } else if (StrUtil.equals("2", logisticsAddressActSelectQJ)) {
            NavLogisticsMapping selectOneMapping = logisticsMappingService.getOne(Wrappers.<NavLogisticsMapping>lambdaQuery().eq(NavLogisticsMapping::getProvinceSimpleName, navSellOrder.getDeliveryProvince()), false);
            if (ObjUtil.isNotEmpty(selectOneMapping)) {
                navSellOrder.setDeliveryProvince(selectOneMapping.getProvinceFullName());
            }
        }
    }

    /**
     * 若收货地址城市为空，使用省/州信息进行填充 2:若收货地址省/州为空，使用城市信息进行填充
     *
     * @param navSellOrder
     * @param logisticsAddressActFill
     */
    public static void logisticsAddressActFill(NavSellOrderVo navSellOrder, String logisticsAddressActFill) {
        if (StrUtil.equals("1", logisticsAddressActFill)) {
            navSellOrder.setDeliveryCity(StrUtil.blankToDefault(navSellOrder.getDeliveryCity(), navSellOrder.getDeliveryProvince()));
        } else if (StrUtil.equals("2", logisticsAddressActFill)) {
            navSellOrder.setDeliveryProvince(StrUtil.blankToDefault(navSellOrder.getDeliveryProvince(), navSellOrder.getDeliveryCity()));
        }
    }

    private void setLogistics(NavOrderRule orderRule, NavSellOrderVo navSellOrder) {
        //设定方式
        String logisticsActSettingMethod = Convert.toStr(orderRule.getLogisticsActSettingMethod(), "0");
        //物流渠道
        Long logisticsActChannel = CollUtil.getFirst(orderRule.getLogisticsActChannel());
        //自动覆盖订单原有物流
        boolean isCoverOriginal = StrUtil.equals("1", Convert.toStr(orderRule.getLogisticsActAutoCoverOriginal(), "0"));
        //1固定物流 2.物流比价
        if (StrUtil.equals("1", logisticsActSettingMethod)) {
            if (ObjUtil.isEmpty(navSellOrder.getDeliveryLogisticsChannel())) {
                navSellOrder.setDeliveryLogisticsChannel(logisticsActChannel);
            } else {
                if (isCoverOriginal) {
                    navSellOrder.setDeliveryLogisticsChannel(logisticsActChannel);
                }
            }
        }
    }

    private void setWarehouse(NavOrderRule orderRule, NavSellOrderVo navSellOrder) {
        boolean isCoverOriginal = StrUtil.equals("1", Convert.toStr(orderRule.getWarehouseActAutoCoverOriginal(), "0"));
        List<NavSellOrderDetailItemVo> searchOrderDetail = navSellOrder.getProduct();
        //发货仓库
        Long warehouseActDeliveryWarehouseId = orderRule.getWarehouseActDeliveryWarehouse();
        //备选仓库
        List<String> optionWarehouseIdList = Convert.toList(String.class, orderRule.getWarehouseActOptionWarehouse());
        //库存扣减类型
        String warehouseActInventoryDeductionType = orderRule.getWarehouseActInventoryDeductionType();
        //判断发货仓库是否有库存
        boolean haveStock = this.isHaveStock(warehouseActDeliveryWarehouseId, warehouseActInventoryDeductionType, searchOrderDetail);
        if (haveStock) {
            setWareHouseId(navSellOrder, isCoverOriginal, warehouseActDeliveryWarehouseId);
        } else {
            for (String aLong : optionWarehouseIdList) {
                boolean haveOptionStock = this.isHaveStock(Convert.toLong(aLong), warehouseActInventoryDeductionType, searchOrderDetail);
                if (haveOptionStock) {
                    setWareHouseId(navSellOrder, isCoverOriginal, Convert.toLong(aLong));
                } else {
                    navSellOrder.setTag(tagHandler(navSellOrder.getTag(), "25"));
                }
            }
        }
    }

    private void setWareHouseId(NavSellOrderVo navSellOrder, boolean isCoverOriginal, Long
            warehouseActDeliveryWarehouseId) {
        if (ObjUtil.isNotEmpty(navSellOrder.getDeliveryWarehouse())) {
            //覆盖原有仓库
            if (isCoverOriginal) {
                navSellOrder.setDeliveryWarehouse(warehouseActDeliveryWarehouseId);
            }
        } else {
            navSellOrder.setDeliveryWarehouse(warehouseActDeliveryWarehouseId);
        }
    }

    //根据扣减类型去查库存
    private boolean isHaveStock(Long warehouseActDeliveryWarehouseId, String
            warehouseActInventoryDeductionType, List<NavSellOrderDetailItemVo> searchOrderDetail) {
        //默认只写sku+空的
        List<Long> productIdList = searchOrderDetail.stream().map(NavSellOrderDetailItemVo::getProductId).filter(id -> id != null).collect(Collectors.toList());
        if (CollUtil.isEmpty(productIdList)) {
            return false;
        }
        //查询即时库存
        //List<InventoryReal> list = inventoryRealService.list(Wrappers.<InventoryReal>query().lambda().eq(InventoryReal::getStockId, warehouseActDeliveryWarehouseId).in(InventoryReal::getItemId, productIdList).isNull(InventoryReal::getShopId).isNull(InventoryReal::getFnSku));
        for (NavSellOrderDetailItemVo itemVo : searchOrderDetail) {
            if (ObjUtil.isEmpty(itemVo.getProductId())) {
                return false;
            }

            NavSellOrderGetInventoryParam param = new NavSellOrderGetInventoryParam();
            param.setStockId(warehouseActDeliveryWarehouseId);
            param.setProducrId(itemVo.getProductId());
            param.setHasZero("1");
            List<NavSellOrderGetInventoryResult> inventoryList = this.getInventory(param).getRecords();
            if (CollUtil.isEmpty(inventoryList)) {
                return false;
            }
            NavSellOrderGetInventoryResult inventory = CollUtil.getFirst(inventoryList);
            itemVo.setAvailableQuantity(Convert.toInt(inventory.getStockqty()));


//            List<InventoryReal> collect = list.stream().filter(x -> NumberUtil.equals(x.getItemId(), itemVo.getProductId()) && NumberUtil.isLessOrEqual(Convert.toBigDecimal(itemVo.getQuantity(), BigDecimal.ZERO), Convert.toBigDecimal(x.getStockQty(), BigDecimal.ZERO))).collect(Collectors.toList());
//            if (CollUtil.isEmpty(collect)) {
//                return false;
//            }
//            InventoryReal inventoryReal = CollUtil.getFirst(collect);
//            itemVo.setAvailableQuantity(Convert.toInt(NumberUtil.sub(Convert.toBigDecimal(inventoryReal.getStockQty(), BigDecimal.ZERO), Convert.toBigDecimal(inventoryReal.getLockQty(), BigDecimal.ZERO))));
        }
        return true;
    }

    private List<NavOrderRule> getNavOrderRule(List<NavOrderRule> collect, NavSellOrderVo navSellOrder) {
        List<NavOrderRule> resultNavOrderRule = new ArrayList<>();
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        //根据基础资料去匹配规则
        for (NavOrderRule orderRule : collect) {
            boolean platform = true;
            boolean site = true;
            boolean shopInfo = true;
            NavSellOrderPlatformItemVo p = CollUtil.getFirst(navSellOrder.getPlatform());
            if (ObjUtil.isNotEmpty(p) && ObjUtil.isNotEmpty(orderRule.getBaseOrderPlatform()) && !StrUtil.equals(orderRule.getBaseOrderPlatform(), p.getPlatform())) {
                platform = false;
            }
            if (ObjUtil.isNotEmpty(orderRule.getBaseOrderSite()) && !CollUtil.safeContains(orderRule.getBaseOrderSite(), navSellOrder.getSite())) {
                site = false;
            }
            if (ObjUtil.isNotEmpty(orderRule.getBaseOrderShopInfo()) && !CollUtil.safeContains(orderRule.getBaseOrderShopInfo(), navSellOrder.getShopInfo())) {
                shopInfo = false;
            }
            if (platform && site && shopInfo) {
                resultNavOrderRule.add(orderRule);
            }
        }
        //根据其他信息去匹配
        return resultNavOrderRule;
    }

    public Boolean checkFbaData(NavSellOrderVo navSellOrderVo) {
        Long wid = navSellOrderVo.getDeliveryWarehouse();
        Assert.notNull(wid, "请选择发货仓库");
        Warehouse warehouse = warehouseService.getById(wid);
        Assert.notNull(warehouse, "未找到仓库");
        ShopInfo shopInfo = shopInfoService.getById(warehouse.getSid());
        Assert.notNull(shopInfo, "未找到对应店铺，请重新选择");

        Boolean isPair = true;
        for (NavSellOrderDetailItemVo product : navSellOrderVo.getProduct()) {
            final ListingFather listingFather = listingFatherService.getOne(Wrappers.lambdaQuery(ListingFather.class)
                    .eq(ListingFather::getShop, shopInfo.getId())
                    .eq(ListingFather::getPairProduct, product.getProductId()), false);
            if (null == listingFather) {
                isPair = false;
            }
        }
        return isPair;
    }


    /**
     * 上传图片
     *
     * @param vo
     * @return
     */
    public Collection getFacePDF(NavSellOrderVo vo, boolean useCache, int dpi) {
        final String GETSHIPPINGLABEL = "EC00487";
        Collection list = new ArrayList<>();
        try {
            if (StrUtil.equals("1", vo.getDeliveryWidType()) && StrUtil.equalsIgnoreCase("EBO", vo.getProviderName())) {
                String fileName = StrUtil.concat(true, vo.getOrderId(), "_", vo.getDeliveryWaybillId(), ".png");
                SysFile fileByFilename = sysFileService.getByFilename(fileName);
                if (ObjUtil.isNotEmpty(fileByFilename) && useCache) {
                    CollUtil.addIfAbsent(list, fileByFilename);
                } else {
                    JSONObject labelParam = new JSONObject();
                    labelParam.put("orderId", vo.getDeliveryWaybillId());
                    String data = Convert.toStr(datainterfaceService.executeInterface(null, GETSHIPPINGLABEL, null, labelParam, null));
                    if (StrUtil.isNotBlank(data) && Base64.isBase64(data)) {
                        MultipartFile multipartFile = this.convertPDF(fileName, Base64.decode(data), dpi);
                        if (ObjUtil.isNotEmpty(multipartFile)) {
                            SysFile upload = fileService.upload(multipartFile, null);
                            CollUtil.addIfAbsent(list, upload);
                        }
                    }
                }

            } else if (StrUtil.equals("1", vo.getDeliveryWidType()) && StrUtil.equalsIgnoreCase("Tiktok", vo.getProviderName())) {
                final List<String> packageIds = Arrays.asList(vo.getPackageIds().split(","));
                for (String packageId : packageIds) {
                    String fileName = StrUtil.concat(true, vo.getOrderId(), "_", packageId, ".png");
                    SysFile fileByFilename = sysFileService.getByFilename(fileName);
                    if (ObjUtil.isNotEmpty(fileByFilename) && useCache) {
                        CollUtil.addIfAbsent(list, fileByFilename);
                    } else {
                        SysFile upload = tiktokOrderService.getPackageShippingDocument(vo.getOrderId(), vo.getPackageIds(), vo.getShopInfo());
                        CollUtil.addIfAbsent(list, upload);
                    }
                }
                return list;
            }
        } catch (Exception ex) {
            CollUtil.addIfAbsent(list, StrUtil.format("系统单号:{}获取面单异常,异常信息:{}", vo.getOrderId(), StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000)));
            //log.error(StrUtil.format("系统单号:{}获取面单异常,异常信息:{}", vo.getOrderId(), StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000)));
        }
        return list;
    }

    /**
     * pdf to jpeg
     *
     * @param fileName
     * @param fileByte
     * @return
     * @throws IOException
     */
    public MultipartFile convertPDF(String fileName, byte[] fileByte, int dpi) throws IOException {
        PDDocument document = PDDocument.load(fileByte);
        PDFRenderer pdfRenderer = new PDFRenderer(document);
        BufferedImage image = pdfRenderer.renderImageWithDPI(0, Convert.toInt(dpi, 1024)); //第一页 dpi:1024
        MockMultipartFile mockMultipartFile = new MockMultipartFile(fileName, fileName, "image/png", ImgUtil.toBytes(image, null));
        return mockMultipartFile;
    }


    /**
     * 生成采购单
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了生成采购单操作"
    )
    @Override
    public void createPurchase(List<Long> ids) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(ids), "参数异常!");
        try {
            List<NavSellOrderVo> list = this.getVoByIdList(ids, true);
            Assert.isTrue(CollUtil.isNotEmpty(list), "请选择对应订单!");
            Assert.isTrue(list.stream().allMatch(a -> CollUtil.safeContains(CollUtil.newArrayList("1"), a.getStatus())), "校验异常,请检查单据状态!");// 1:待审核 2:待发货 3:发货中 4:已发货 5:平台发货 -1:已取消 -2:已冻结

            PurchaseOrderSearchParamPo searchParamPo = new PurchaseOrderSearchParamPo();
            searchParamPo.setPurNumSearInList(list.stream().map(m -> m.getOrderId()).collect(Collectors.toList()));
            Page<PurchaseOrderItemVo> purchaseOrderItemVoPage = purchaseOrderService.pageSearch(searchParamPo);
            Assert.isTrue(CollUtil.isEmpty(purchaseOrderItemVoPage.getRecords()), "重复生成采购单,请检查!");

            for (NavSellOrderVo orderVo : list) {
                this.prepareTranslatePurchaseOrder(orderVo);
                PurchaseOrderVo purchaseOrderVo = this.translatePurchaseOrder(orderVo);
                purchaseOrderService.create(purchaseOrderVo);
            }
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    private PurchaseOrderVo translatePurchaseOrder(NavSellOrderVo source) throws Exception {
        if (ObjUtil.isEmpty(source)) {
            return null;
        }
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        List<NavSellOrderDetailItemVo> productList = source.getProduct();
        PurchaseOrderVo target = new PurchaseOrderVo();
        target.setSupplierId(null); //供应商
        target.setSupplierName(null); //供应商名称
        target.setWid(source.getDeliveryWarehouse());  //仓库
        target.setWarehouseName(SpringUtil.getBean(WarehouseService.class).getNameById(source.getDeliveryWarehouse())); //仓库名
        target.setContactPerson(null); //联系人
        target.setContactNumber(null); //联系电话
        target.setSettlementMethod("JS01"); //结算方式  JS01:现结  JS02:月结
        target.setAdvanceRatio(BigDecimal.ZERO); // 预付比例
        target.setSettlementDescribe(null); //结算描述
        target.setPaymentMethod("ZF02"); //支付方式  ZF01:网银转账  ZF02:网上支付
        target.setPurchaseCurrency("CNY"); //采购币种
        target.setShippingPrice(BigDecimal.ZERO); //运费
        target.setOtherCurrency(BigDecimal.ZERO); //其它费用
        target.setFeePartType("0"); //费用分摊方式 (0 -  不分摊; 1 - 按金额; 2 -  按数量; )
        target.setIncludingTax("0"); //含税
        target.setOptUid(this.getUser(currentUser).getUserId()); //采购员
        target.setPurchaser(null); //采购方
        target.setProductType("1"); //产品类型 (0 - 原材料; 1 - 成品; )
        target.setOversightUid(CollUtil.newArrayList(this.getUser(currentUser).getUserId())); //单据负责人
        target.setInspectionType("0"); //质检类型 (0 - 仓库质检; 1 - 预检; 2 - 免检; )
        target.setRemarks(null); //备注
        target.setTotalPrice("0"); //总金额
        target.setQuantityReceived(0L); //到货量

        target.setOrgName(this.getUser(currentUser).getOrganizationName()); //组织名称
        target.setOrgId(this.getUser(currentUser).getOrganizationId()); //组织

        target.setApplicationDep(this.getUser(currentUser).getDepId()); //申请部门
        target.setApplication(this.getUser(currentUser).getUserName()); //申请人
        target.setStauts("0"); //状态

        target.setPurchasesDate(new Date()); //采购日期
        target.setApplicationDepName1(this.getUser(currentUser).getDepName()); //申请部门
        target.setPurchaseQuantity(Convert.toStr(NumberUtil.add(productList.stream().map(NavSellOrderDetailItemVo::getQuantity).toArray(Integer[]::new)), "0")); //采购数量
        target.setAnStatus("0"); //审批状态 (-1 - 作废; 0 - 待提交; 1 - 待下单; 2 - 待到货; 9 - 已完成; 121 - 待审核(审批流); 122 - 驳回(审批流); 124 - 作废(审批流); )
        target.setPurNumSear(source.getOrderId()); //采购单号
        target.setLogOrderSear(null); //物流单号
        target.setPlanOrderSear(null); //计划编号
        target.setNumOrderSear(null); //1688订单号
        target.setOrderRemarkSear(StrUtil.format("自发货订单号{}", source.getOrderId())); //单据备注
        target.setPurSear(this.getUser(currentUser).getUserName()); //采购员
        target.setFile(null);
        target.setCrossChecking(null); //退款勾稽字段
        target.setArrivalStatus("0"); //到货状态 (0 - 未到货; 1 - 部分到货; 2 - 全部到货; )
        target.setOrderTime(new Date()); //下单时间
        target.setSupplierCode(null); //供应商代码
        target.setWcode(null); //仓库编码
        target.setPayStatus("0"); //付款状态 (0 - 未申请; 1 - 已申请; 2 - 部分付款; 3 - 已付款; )
        target.setPurchasesOrg(this.getUser(currentUser).getOrganizationId()); //采购组织
        target.setSettlementOrg(this.getUser(currentUser).getOrganizationId()); //结算组织
        target.setUrgentOrNot("1"); //加急 (0 - 是; 1 - 否; )
        target.setOrderUser(this.getUser(currentUser).getUserId()); //下单人
        target.setProgresslog(null); //进度日志
        target.setCreateTime(new Date());
        target.setLastUpdateTime(new Date());
        //如果存在当前用户
        if (currentUser != null) {
            target.setCreateUser(currentUser.getUserId());
            target.setLastUpdateUser(currentUser.getUserId());
        }
        List<PurchaseOrderProductItemVo> sourceItemList = new ArrayList<>();
        for (NavSellOrderDetailItemVo product : productList) {
            ProductVo productVo = SpringUtil.getBean(ProductServiceImpl.class).getVoById(product.getProductId());
            PurchaseOrderProductItemVo targetItem = new PurchaseOrderProductItemVo();
            targetItem.setApplicationDep(this.getUser(currentUser).getDepName()); //需求部门
            targetItem.setPicUrl(product.getImg()); //图片
            targetItem.setBusinessIdent(null); //业务标识 ?
            targetItem.setProductId(product.getProductId()); //产品
            targetItem.setProductIdName(product.getProductIdName()); //关联产品的品名
            targetItem.setSku(product.getSku()); //SKU
            targetItem.setProductName(product.getProductIdName()); //品名
            targetItem.setTag(null); //标签
            targetItem.setSid(source.getShopInfo()); //店铺
            targetItem.setSidShopName(SpringUtil.getBean(ShopInfoService.class).getShopNameById(source.getShopInfo())); //关联店铺的名称
            targetItem.setMsku(product.getMsku()); //MSKU
            targetItem.setFnsku(null); //FNSKU
            targetItem.setFnskuFnsku(null); //关联FNSKU的FNSKU
            targetItem.setModel(null); //型号
            targetItem.setApplicationNum(product.getQuantity()); //采购数量
            targetItem.setTaxPrice(BigDecimal.ZERO); //含税单价
            targetItem.setSupplierQuotation(BigDecimal.ZERO); //供应商报价
            targetItem.setUnitPrice(BigDecimal.ZERO); //单价
            targetItem.setCostPrice(productVo.getProcurementCost()); //成本价格
            targetItem.setMainUnitPrice(BigDecimal.ZERO); //主材料单价
            targetItem.setGramWeight(productVo.getProductGross()); //主材料克重
            targetItem.setLaborCosts(BigDecimal.ZERO); //工费
            targetItem.setAccessoriesPrice(BigDecimal.ZERO); //辅料
            targetItem.setMaterialloss(BigDecimal.ZERO); //损耗%
            targetItem.setMaterialpack(BigDecimal.ZERO); //包装
            targetItem.setErpprice(BigDecimal.ZERO); //ERP价格
            targetItem.setTaxRate(BigDecimal.ZERO); //税率
            targetItem.setTaxAmount(BigDecimal.ZERO); //税额
            targetItem.setTotalPrice(BigDecimal.ZERO); //金额
            targetItem.setAmount(BigDecimal.ZERO); //价税合计
            targetItem.setQuantityReceived(0); //到货量
            targetItem.setQuantityReceive(0); //待到货量
            targetItem.setQuantityReturn(0); //退货量
            targetItem.setEndDifferenceQuantity(0); //结束差异量
            targetItem.setExpectArriveTime(null); //预计到货时间
            targetItem.setArrivalDate(null); //到货日期
            targetItem.setApplicationUnit(this.getUser(currentUser).getDepName()); //采购单位
            targetItem.setInventoryUnit(this.getUser(currentUser).getDepName()); //库存单位
            targetItem.setPurchaseOrderId(null); //所属采购订单
            targetItem.setPurchaseOrderIdPurchaseOrderCode(null); //关联所属采购订单的采购单号
            targetItem.setRemarks(null); //备注
            targetItem.setPlanSn(null); //采购计划编号
            targetItem.setCrossQty(0L); //下推贷款现结源表勾稽字段
            targetItem.setLocalShopInventory(Convert.toLong(product.getAvailableQuantity())); //本店铺的库存
            targetItem.setOtherShopInventory(0L); //其他店铺的库存
            targetItem.setPublicInventory(0L); //公共的库存
            targetItem.setThreeSalesVolume(0L); //3天销量
            targetItem.setSevenSalesVolume(0L); //7天销量
            targetItem.setThirtySalesVolume(0L); //30天销量
            targetItem.setCrossChecking(0L); //退款勾稽字段
            targetItem.setScode(Convert.toStr(source.getShopInfo())); //店铺编号
            targetItem.setLxPrice(BigDecimal.ZERO); //领星价格
            targetItem.setLxTotalPrice(BigDecimal.ZERO); //领星价格合计
            targetItem.setLxFnsku(null); //领星fnsku
            targetItem.setLocalDayList(null); //本地库龄
            targetItem.setFbaDayList(null); //fba
            targetItem.setSkuSales(null); //销量
            targetItem.setSameSales(null); //同期销量
            targetItem.setWfStatus(null); //工作流状态

            targetItem.setCreateTime(new Date());
            targetItem.setLastUpdateTime(new Date());
            //如果存在当前用户
            if (currentUser != null) {
                targetItem.setCreateUser(currentUser.getUserId());
                targetItem.setLastUpdateUser(currentUser.getUserId());
            }
            sourceItemList.add(targetItem);
        }
        target.setPurchaseOrde(sourceItemList);
        return target;
    }

    /**
     * 预处理转换
     *
     * @param source
     */
    private void prepareTranslatePurchaseOrder(NavSellOrderVo source) {
        Assert.isTrue(ObjUtil.isNotEmpty(source), "数据源不能为空");
        NavSellOrderPlatformItemVo platform = CollUtil.getFirst(source.getPlatform());
        Assert.isTrue(ObjUtil.isNotEmpty(platform) && StrUtil.equals("Jewelry", platform.getPlatform()), "只有独立站订单支持此操作!");
        Assert.isTrue(!this.hasTagHandler(source.getTag(), "4"), "商品未配对,不支持此操作!");
        Assert.isTrue(StrUtil.equals("1", source.getDeliveryWidType()), "只有本地仓订单支持此操作!");
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    private CustomSysUserVo getUser(JwtUserInfo currentUser) {
        CustomSysUserVo userVo = new CustomSysUserVo();
        if (ObjUtil.isNotEmpty(currentUser)) {
            userVo.setUserId(currentUser.getUserId());
            userVo.setUserName(currentUser.getDisplayName());
            SysUserVo sysUserVo = SpringUtil.getBean(SysUserServiceImpl.class).getVoById(currentUser.getUserId());
            if (ObjUtil.isEmpty(sysUserVo)) {
                return userVo;
            }
            Long organizationId = SpringUtil.getBean(DbOrganizationService.class).getIdByName("苏发");
            if (ObjUtil.isNotEmpty(organizationId)) {
                userVo.setOrganizationName("苏发"); //组织名称
                userVo.setOrganizationId(organizationId); //组织
            }
            if (CollUtil.isNotEmpty(sysUserVo.getDepartmentIds())) {
                userVo.setDepId(CollUtil.getFirst(sysUserVo.getDepartmentIds()));
                SysDepartment sysDepartment = SpringUtil.getBean(SysDepartmentServiceImpl.class).getById(CollUtil.getFirst(sysUserVo.getDepartmentIds()));
                userVo.setDepName(ObjUtil.isEmpty(sysDepartment) ? null : sysDepartment.getName());
            }
        }
        return userVo;
    }

}